aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-02-21 09:21:11 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-02-21 09:29:49 +0300
commit7732db443bee366753d1b056727860be4b833df0 (patch)
tree5d69ae560f055f7b9ff27ebee26440dc19eb6e86
parent705f460d33000009c49a47b51913a7f29d2d6c46 (diff)
downloadydb-7732db443bee366753d1b056727860be4b833df0.tar.gz
Intermediate changes
-rw-r--r--contrib/python/appnope/py3/.dist-info/METADATA11
-rw-r--r--contrib/python/appnope/py3/appnope/__init__.py10
-rw-r--r--contrib/python/appnope/py3/appnope/_dummy.py16
-rw-r--r--contrib/python/appnope/py3/appnope/_nope.py72
-rw-r--r--contrib/python/appnope/py3/ya.make2
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA34
-rw-r--r--contrib/python/fonttools/README.rst2
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/designspaceLib/__init__.py68
-rw-r--r--contrib/python/fonttools/fontTools/designspaceLib/__main__.py6
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/builder.py32
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/lexer.py4
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/parser.py8
-rw-r--r--contrib/python/fonttools/fontTools/otlLib/builder.py54
-rw-r--r--contrib/python/fonttools/fontTools/pens/hashPointPen.py14
-rw-r--r--contrib/python/fonttools/fontTools/pens/roundingPen.py46
-rw-r--r--contrib/python/fonttools/fontTools/pens/svgPathPen.py20
-rw-r--r--contrib/python/fonttools/fontTools/subset/__init__.py3
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/tables/otTables.py35
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/tables/sbixGlyph.py14
-rw-r--r--contrib/python/fonttools/fontTools/varLib/__init__.py8
-rw-r--r--contrib/python/fonttools/fontTools/varLib/instancer/__init__.py2
-rw-r--r--contrib/python/fonttools/ya.make3
23 files changed, 310 insertions, 156 deletions
diff --git a/contrib/python/appnope/py3/.dist-info/METADATA b/contrib/python/appnope/py3/.dist-info/METADATA
index 9c7b757060..76ef35d8e7 100644
--- a/contrib/python/appnope/py3/.dist-info/METADATA
+++ b/contrib/python/appnope/py3/.dist-info/METADATA
@@ -1,20 +1,15 @@
Metadata-Version: 2.1
Name: appnope
-Version: 0.1.3
+Version: 0.1.4
Summary: Disable App Nap on macOS >= 10.9
Home-page: http://github.com/minrk/appnope
Author: Min Ragan-Kelley
Author-email: benjaminrk@gmail.com
License: BSD
-Platform: UNKNOWN
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: MacOS :: MacOS X
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
+Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
@@ -48,5 +43,3 @@ It uses ctypes to wrap a `[NSProcessInfo beginActivityWithOptions]` call to disa
To install:
pip install appnope
-
-
diff --git a/contrib/python/appnope/py3/appnope/__init__.py b/contrib/python/appnope/py3/appnope/__init__.py
index bcf87f4917..c447f24185 100644
--- a/contrib/python/appnope/py3/appnope/__init__.py
+++ b/contrib/python/appnope/py3/appnope/__init__.py
@@ -1,13 +1,15 @@
-__version__ = '0.1.3'
+__version__ = "0.1.4"
import re
import sys
import platform
+
def _v(version_s):
- return tuple(int(s) for s in re.findall("\d+", version_s))
+ return tuple(int(s) for s in re.findall(r"\d+", version_s))
+
if sys.platform != "darwin" or _v(platform.mac_ver()[0]) < _v("10.9"):
- from ._dummy import *
+ from ._dummy import * # noqa
else:
- from ._nope import *
+ from ._nope import * # noqa
diff --git a/contrib/python/appnope/py3/appnope/_dummy.py b/contrib/python/appnope/py3/appnope/_dummy.py
index a55ec5bfcd..a4ee06f89e 100644
--- a/contrib/python/appnope/py3/appnope/_dummy.py
+++ b/contrib/python/appnope/py3/appnope/_dummy.py
@@ -1,30 +1,32 @@
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Copyright (C) 2013 Min RK
#
# Distributed under the terms of the 2-clause BSD License.
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
from contextlib import contextmanager
+
def beginActivityWithOptions(options, reason=""):
return
+
def endActivity(activity):
return
+
def nope():
return
+
def nap():
return
@contextmanager
-def nope_scope(
- options=0,
- reason="Because Reasons"
- ):
+def nope_scope(options=0, reason="Because Reasons"):
yield
+
def napping_allowed():
- return True \ No newline at end of file
+ return True
diff --git a/contrib/python/appnope/py3/appnope/_nope.py b/contrib/python/appnope/py3/appnope/_nope.py
index d83e826797..10d1c056f4 100644
--- a/contrib/python/appnope/py3/appnope/_nope.py
+++ b/contrib/python/appnope/py3/appnope/_nope.py
@@ -1,16 +1,16 @@
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# Copyright (C) 2013 Min RK
#
# Distributed under the terms of the 2-clause BSD License.
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
from contextlib import contextmanager
import ctypes
import ctypes.util
-objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
-_ = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Foundation'))
+objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc"))
+_ = ctypes.cdll.LoadLibrary(ctypes.util.find_library("Foundation"))
void_p = ctypes.c_void_p
ull = ctypes.c_uint64
@@ -22,74 +22,82 @@ objc.objc_msgSend.argtypes = [void_p, void_p]
msg = objc.objc_msgSend
+
def _utf8(s):
"""ensure utf8 bytes"""
if not isinstance(s, bytes):
- s = s.encode('utf8')
+ s = s.encode("utf8")
return s
+
def n(name):
"""create a selector name (for methods)"""
return objc.sel_registerName(_utf8(name))
+
def C(classname):
"""get an ObjC Class by name"""
ret = objc.objc_getClass(_utf8(classname))
assert ret is not None, "Couldn't find Class %s" % classname
return ret
+
# constants from Foundation
-NSActivityIdleDisplaySleepDisabled = (1 << 40)
-NSActivityIdleSystemSleepDisabled = (1 << 20)
-NSActivitySuddenTerminationDisabled = (1 << 14)
-NSActivityAutomaticTerminationDisabled = (1 << 15)
-NSActivityUserInitiated = (0x00FFFFFF | NSActivityIdleSystemSleepDisabled)
-NSActivityUserInitiatedAllowingIdleSystemSleep = (NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled)
-NSActivityBackground = 0x000000FF
-NSActivityLatencyCritical = 0xFF00000000
+NSActivityIdleDisplaySleepDisabled = 1 << 40
+NSActivityIdleSystemSleepDisabled = 1 << 20
+NSActivitySuddenTerminationDisabled = 1 << 14
+NSActivityAutomaticTerminationDisabled = 1 << 15
+NSActivityUserInitiated = 0x00FFFFFF | NSActivityIdleSystemSleepDisabled
+NSActivityUserInitiatedAllowingIdleSystemSleep = (
+ NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled
+)
+NSActivityBackground = 0x000000FF
+NSActivityLatencyCritical = 0xFF00000000
+
def beginActivityWithOptions(options, reason=""):
"""Wrapper for:
-
- [ [ NSProcessInfo processInfo]
+
+ [ [ NSProcessInfo processInfo]
beginActivityWithOptions: (uint64)options
reason: (str)reason
]
"""
- NSProcessInfo = C('NSProcessInfo')
- NSString = C('NSString')
-
+ NSProcessInfo = C("NSProcessInfo")
+ NSString = C("NSString")
+
objc.objc_msgSend.argtypes = [void_p, void_p, void_p]
reason = msg(NSString, n("stringWithUTF8String:"), _utf8(reason))
objc.objc_msgSend.argtypes = [void_p, void_p]
- info = msg(NSProcessInfo, n('processInfo'))
+ info = msg(NSProcessInfo, n("processInfo"))
objc.objc_msgSend.argtypes = [void_p, void_p, ull, void_p]
- activity = msg(info,
- n('beginActivityWithOptions:reason:'),
- ull(options),
- void_p(reason)
+ activity = msg(
+ info, n("beginActivityWithOptions:reason:"), ull(options), void_p(reason)
)
return activity
+
def endActivity(activity):
"""end a process activity assertion"""
- NSProcessInfo = C('NSProcessInfo')
+ NSProcessInfo = C("NSProcessInfo")
objc.objc_msgSend.argtypes = [void_p, void_p]
- info = msg(NSProcessInfo, n('processInfo'))
+ info = msg(NSProcessInfo, n("processInfo"))
objc.objc_msgSend.argtypes = [void_p, void_p, void_p]
msg(info, n("endActivity:"), void_p(activity))
+
_theactivity = None
+
def nope():
"""disable App Nap by setting NSActivityUserInitiatedAllowingIdleSystemSleep"""
global _theactivity
_theactivity = beginActivityWithOptions(
- NSActivityUserInitiatedAllowingIdleSystemSleep,
- "Because Reasons"
+ NSActivityUserInitiatedAllowingIdleSystemSleep, "Because Reasons"
)
+
def nap():
"""end the caffeinated state started by `nope`"""
global _theactivity
@@ -97,17 +105,18 @@ def nap():
endActivity(_theactivity)
_theactivity = None
+
def napping_allowed():
"""is napping allowed?"""
return _theactivity is None
+
@contextmanager
def nope_scope(
- options=NSActivityUserInitiatedAllowingIdleSystemSleep,
- reason="Because Reasons"
- ):
+ options=NSActivityUserInitiatedAllowingIdleSystemSleep, reason="Because Reasons"
+):
"""context manager for beginActivityWithOptions.
-
+
Within this context, App Nap will be disabled.
"""
activity = beginActivityWithOptions(options, reason)
@@ -116,6 +125,7 @@ def nope_scope(
finally:
endActivity(activity)
+
__all__ = [
"NSActivityIdleDisplaySleepDisabled",
"NSActivityIdleSystemSleepDisabled",
diff --git a/contrib/python/appnope/py3/ya.make b/contrib/python/appnope/py3/ya.make
index bacfa9a91b..a1901177d1 100644
--- a/contrib/python/appnope/py3/ya.make
+++ b/contrib/python/appnope/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(0.1.3)
+VERSION(0.1.4)
LICENSE(BSD-2-Clause)
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index f9e01c388f..b335b936d7 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 4.47.2
+Version: 4.48.1
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -31,7 +31,7 @@ Requires-Python: >=3.8
License-File: LICENSE
Provides-Extra: all
Requires-Dist: fs <3,>=2.2.0 ; extra == 'all'
-Requires-Dist: lxml <5,>=4.0 ; extra == 'all'
+Requires-Dist: lxml >=4.0 ; extra == 'all'
Requires-Dist: zopfli >=0.1.4 ; extra == 'all'
Requires-Dist: lz4 >=1.7.4.2 ; extra == 'all'
Requires-Dist: pycairo ; extra == 'all'
@@ -52,7 +52,7 @@ Requires-Dist: pycairo ; extra == 'interpolatable'
Requires-Dist: scipy ; (platform_python_implementation != "PyPy") and extra == 'interpolatable'
Requires-Dist: munkres ; (platform_python_implementation == "PyPy") and extra == 'interpolatable'
Provides-Extra: lxml
-Requires-Dist: lxml <5,>=4.0 ; extra == 'lxml'
+Requires-Dist: lxml >=4.0 ; extra == 'lxml'
Provides-Extra: pathops
Requires-Dist: skia-pathops >=0.5.0 ; extra == 'pathops'
Provides-Extra: plot
@@ -118,7 +118,7 @@ Python 3 `venv <https://docs.python.org/3/library/venv.html>`__ module.
# create new virtual environment called e.g. 'fonttools-venv', or anything you like
python -m virtualenv fonttools-venv
- # source the `activate` shell script to enter the environment (Un*x); to exit, just type `deactivate`
+ # source the `activate` shell script to enter the environment (Unix-like); to exit, just type `deactivate`
. fonttools-venv/bin/activate
# to activate the virtual environment in Windows `cmd.exe`, do
@@ -375,6 +375,32 @@ Have fun!
Changelog
~~~~~~~~~
+4.48.1 (released 2024-02-06)
+----------------------------
+
+- Fixed uploading wheels to PyPI, no code changes since v4.48.0.
+
+4.48.0 (released 2024-02-06)
+----------------------------
+
+- [varLib] Do not log when there are no OTL tables to be merged.
+- [setup.py] Do not restrict lxml<5 any more, tests pass just fine with lxml>=5.
+- [feaLib] Remove glyph and class names length restrictions in FEA (#3424).
+- [roundingPens] Added ``transformRoundFunc`` parameter to the rounding pens to allow
+ for custom rounding of the components' transforms (#3426).
+- [feaLib] Keep declaration order of ligature components within a ligature set, instead
+ of sorting by glyph name (#3429).
+- [feaLib] Fixed ordering of alternates in ``aalt`` lookups, following the declaration
+ order of feature references within the ``aalt`` feature block (#3430).
+- [varLib.instancer] Fixed a bug in the instancer's IUP optimization (#3432).
+- [sbix] Support sbix glyphs with new graphicType "flip" (#3433).
+- [svgPathPen] Added ``--glyphs`` option to dump the SVG paths for the named glyphs
+ in the font (0572f78).
+- [designspaceLib] Added "description" attribute to ``<mappings>`` and ``<mapping>``
+ elements, and allow multiple ``<mappings>`` elements to group ``<mapping>`` elements
+ that are logically related (#3435, #3437).
+- [otlLib] Correctly choose the most compact GSUB contextual lookup format (#3439).
+
4.47.2 (released 2024-01-11)
----------------------------
diff --git a/contrib/python/fonttools/README.rst b/contrib/python/fonttools/README.rst
index d84282fc76..2274fbdc69 100644
--- a/contrib/python/fonttools/README.rst
+++ b/contrib/python/fonttools/README.rst
@@ -44,7 +44,7 @@ Python 3 `venv <https://docs.python.org/3/library/venv.html>`__ module.
# create new virtual environment called e.g. 'fonttools-venv', or anything you like
python -m virtualenv fonttools-venv
- # source the `activate` shell script to enter the environment (Un*x); to exit, just type `deactivate`
+ # source the `activate` shell script to enter the environment (Unix-like); to exit, just type `deactivate`
. fonttools-venv/bin/activate
# to activate the virtual environment in Windows `cmd.exe`, do
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index 7410d3c7fe..feb093929e 100644
--- a/contrib/python/fonttools/fontTools/__init__.py
+++ b/contrib/python/fonttools/fontTools/__init__.py
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "4.47.2"
+version = __version__ = "4.48.1"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/designspaceLib/__init__.py b/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
index 69d4912c09..d6789f5f61 100644
--- a/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
+++ b/contrib/python/fonttools/fontTools/designspaceLib/__init__.py
@@ -476,7 +476,14 @@ class AxisMappingDescriptor(SimpleDescriptor):
_attrs = ["inputLocation", "outputLocation"]
- def __init__(self, *, inputLocation=None, outputLocation=None):
+ def __init__(
+ self,
+ *,
+ inputLocation=None,
+ outputLocation=None,
+ description=None,
+ groupDescription=None,
+ ):
self.inputLocation: SimpleLocationDict = inputLocation or {}
"""dict. Axis values for the input of the mapping, in design space coordinates.
@@ -491,6 +498,20 @@ class AxisMappingDescriptor(SimpleDescriptor):
.. versionadded:: 5.1
"""
+ self.description = description
+ """string. A description of the mapping.
+
+ varLib.
+
+ .. versionadded:: 5.2
+ """
+ self.groupDescription = groupDescription
+ """string. A description of the group of mappings.
+
+ varLib.
+
+ .. versionadded:: 5.2
+ """
class InstanceDescriptor(SimpleDescriptor):
@@ -1421,10 +1442,19 @@ class BaseDocWriter(object):
self._addAxis(axisObject)
if self.documentObject.axisMappings:
- mappingsElement = ET.Element("mappings")
- self.root.findall(".axes")[0].append(mappingsElement)
+ mappingsElement = None
+ lastGroup = object()
for mappingObject in self.documentObject.axisMappings:
+ if getattr(mappingObject, "groupDescription", None) != lastGroup:
+ if mappingsElement is not None:
+ self.root.findall(".axes")[0].append(mappingsElement)
+ lastGroup = getattr(mappingObject, "groupDescription", None)
+ mappingsElement = ET.Element("mappings")
+ if lastGroup is not None:
+ mappingsElement.attrib["description"] = lastGroup
self._addAxisMapping(mappingsElement, mappingObject)
+ if mappingsElement is not None:
+ self.root.findall(".axes")[0].append(mappingsElement)
if self.documentObject.locationLabels:
labelsElement = ET.Element("labels")
@@ -1586,6 +1616,8 @@ class BaseDocWriter(object):
def _addAxisMapping(self, mappingsElement, mappingObject):
mappingElement = ET.Element("mapping")
+ if getattr(mappingObject, "description", None) is not None:
+ mappingElement.attrib["description"] = mappingObject.description
for what in ("inputLocation", "outputLocation"):
whatObject = getattr(mappingObject, what, None)
if whatObject is None:
@@ -2081,10 +2113,11 @@ class BaseDocReader(LogMixin):
self.documentObject.axes.append(axisObject)
self.axisDefaults[axisObject.name] = axisObject.default
- mappingsElement = self.root.find(".axes/mappings")
self.documentObject.axisMappings = []
- if mappingsElement is not None:
+ for mappingsElement in self.root.findall(".axes/mappings"):
+ groupDescription = mappingsElement.attrib.get("description")
for mappingElement in mappingsElement.findall("mapping"):
+ description = mappingElement.attrib.get("description")
inputElement = mappingElement.find("input")
outputElement = mappingElement.find("output")
inputLoc = {}
@@ -2098,7 +2131,10 @@ class BaseDocReader(LogMixin):
value = float(dimElement.attrib["xvalue"])
outputLoc[name] = value
axisMappingObject = self.axisMappingDescriptorClass(
- inputLocation=inputLoc, outputLocation=outputLoc
+ inputLocation=inputLoc,
+ outputLocation=outputLoc,
+ description=description,
+ groupDescription=groupDescription,
)
self.documentObject.axisMappings.append(axisMappingObject)
@@ -3279,3 +3315,23 @@ class DesignSpaceDocument(LogMixin, AsDictMixin):
finally:
for source, font in zip(self.sources, fonts):
source.font = font
+
+
+def main(args=None):
+ """Roundtrip .designspace file through the DesignSpaceDocument class"""
+
+ if args is None:
+ import sys
+
+ args = sys.argv[1:]
+
+ from argparse import ArgumentParser
+
+ parser = ArgumentParser(prog="designspaceLib", description=main.__doc__)
+ parser.add_argument("input")
+ parser.add_argument("output")
+
+ options = parser.parse_args(args)
+
+ ds = DesignSpaceDocument.fromfile(options.input)
+ ds.write(options.output)
diff --git a/contrib/python/fonttools/fontTools/designspaceLib/__main__.py b/contrib/python/fonttools/fontTools/designspaceLib/__main__.py
new file mode 100644
index 0000000000..8f5e44ea9e
--- /dev/null
+++ b/contrib/python/fonttools/fontTools/designspaceLib/__main__.py
@@ -0,0 +1,6 @@
+import sys
+from fontTools.designspaceLib import main
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/contrib/python/fonttools/fontTools/feaLib/builder.py b/contrib/python/fonttools/fontTools/feaLib/builder.py
index 36eed95148..7921a3f179 100644
--- a/contrib/python/fonttools/fontTools/feaLib/builder.py
+++ b/contrib/python/fonttools/fontTools/feaLib/builder.py
@@ -285,7 +285,11 @@ class Builder(object):
def build_feature_aalt_(self):
if not self.aalt_features_ and not self.aalt_alternates_:
return
- alternates = {g: set(a) for g, a in self.aalt_alternates_.items()}
+ # > alternate glyphs will be sorted in the order that the source features
+ # > are named in the aalt definition, not the order of the feature definitions
+ # > in the file. Alternates defined explicitly ... will precede all others.
+ # https://github.com/fonttools/fonttools/issues/836
+ alternates = {g: list(a) for g, a in self.aalt_alternates_.items()}
for location, name in self.aalt_features_ + [(None, "aalt")]:
feature = [
(script, lang, feature, lookups)
@@ -302,17 +306,14 @@ class Builder(object):
lookuplist = [lookuplist]
for lookup in lookuplist:
for glyph, alts in lookup.getAlternateGlyphs().items():
- alternates.setdefault(glyph, set()).update(alts)
+ alts_for_glyph = alternates.setdefault(glyph, [])
+ alts_for_glyph.extend(
+ g for g in alts if g not in alts_for_glyph
+ )
single = {
- glyph: list(repl)[0] for glyph, repl in alternates.items() if len(repl) == 1
- }
- # TODO: Figure out the glyph alternate ordering used by makeotf.
- # https://github.com/fonttools/fonttools/issues/836
- multi = {
- glyph: sorted(repl, key=self.font.getGlyphID)
- for glyph, repl in alternates.items()
- if len(repl) > 1
+ glyph: repl[0] for glyph, repl in alternates.items() if len(repl) == 1
}
+ multi = {glyph: repl for glyph, repl in alternates.items() if len(repl) > 1}
if not single and not multi:
return
self.features_ = {
@@ -1249,8 +1250,9 @@ class Builder(object):
def add_single_subst(self, location, prefix, suffix, mapping, forceChain):
if self.cur_feature_name_ == "aalt":
for from_glyph, to_glyph in mapping.items():
- alts = self.aalt_alternates_.setdefault(from_glyph, set())
- alts.add(to_glyph)
+ alts = self.aalt_alternates_.setdefault(from_glyph, [])
+ if to_glyph not in alts:
+ alts.append(to_glyph)
return
if prefix or suffix or forceChain:
self.add_single_subst_chained_(location, prefix, suffix, mapping)
@@ -1303,8 +1305,8 @@ class Builder(object):
# GSUB 3
def add_alternate_subst(self, location, prefix, glyph, suffix, replacement):
if self.cur_feature_name_ == "aalt":
- alts = self.aalt_alternates_.setdefault(glyph, set())
- alts.update(replacement)
+ alts = self.aalt_alternates_.setdefault(glyph, [])
+ alts.extend(g for g in replacement if g not in alts)
return
if prefix or suffix:
chain = self.get_lookup_(location, ChainContextSubstBuilder)
@@ -1338,7 +1340,7 @@ class Builder(object):
# substitutions to be specified on target sequences that contain
# glyph classes, the implementation software will enumerate
# all specific glyph sequences if glyph classes are detected"
- for g in sorted(itertools.product(*glyphs)):
+ for g in itertools.product(*glyphs):
lookup.ligatures[g] = replacement
# GSUB 5/6
diff --git a/contrib/python/fonttools/fontTools/feaLib/lexer.py b/contrib/python/fonttools/fontTools/feaLib/lexer.py
index e0ae0aefee..5867f70b38 100644
--- a/contrib/python/fonttools/fontTools/feaLib/lexer.py
+++ b/contrib/python/fonttools/fontTools/feaLib/lexer.py
@@ -111,10 +111,6 @@ class Lexer(object):
glyphclass = text[start + 1 : self.pos_]
if len(glyphclass) < 1:
raise FeatureLibError("Expected glyph class name", location)
- if len(glyphclass) > 63:
- raise FeatureLibError(
- "Glyph class names must not be longer than 63 characters", location
- )
if not Lexer.RE_GLYPHCLASS.match(glyphclass):
raise FeatureLibError(
"Glyph class names must consist of letters, digits, "
diff --git a/contrib/python/fonttools/fontTools/feaLib/parser.py b/contrib/python/fonttools/fontTools/feaLib/parser.py
index 8ffdf644c3..8cbe79592b 100644
--- a/contrib/python/fonttools/fontTools/feaLib/parser.py
+++ b/contrib/python/fonttools/fontTools/feaLib/parser.py
@@ -2071,13 +2071,7 @@ class Parser(object):
def expect_glyph_(self):
self.advance_lexer_()
if self.cur_token_type_ is Lexer.NAME:
- self.cur_token_ = self.cur_token_.lstrip("\\")
- if len(self.cur_token_) > 63:
- raise FeatureLibError(
- "Glyph names must not be longer than 63 characters",
- self.cur_token_location_,
- )
- return self.cur_token_
+ return self.cur_token_.lstrip("\\")
elif self.cur_token_type_ is Lexer.CID:
return "cid%05d" % self.cur_token_
raise FeatureLibError("Expected a glyph name or CID", self.cur_token_location_)
diff --git a/contrib/python/fonttools/fontTools/otlLib/builder.py b/contrib/python/fonttools/fontTools/otlLib/builder.py
index 4b457f4d9f..c8b14fc666 100644
--- a/contrib/python/fonttools/fontTools/otlLib/builder.py
+++ b/contrib/python/fonttools/fontTools/otlLib/builder.py
@@ -6,6 +6,7 @@ from fontTools.ttLib.tables import otTables as ot
from fontTools.ttLib.tables.otBase import (
ValueRecord,
valueRecordFormatDict,
+ OTLOffsetOverflowError,
OTTableWriter,
CountReference,
)
@@ -350,16 +351,14 @@ class ChainContextualBuilder(LookupBuilder):
return [x for x in ruleset if len(x.rules) > 0]
def getCompiledSize_(self, subtables):
- size = 0
- for st in subtables:
- w = OTTableWriter()
- w["LookupType"] = CountReference(
- {"LookupType": st.LookupType}, "LookupType"
- )
- # We need to make a copy here because compiling
- # modifies the subtable (finalizing formats etc.)
- copy.deepcopy(st).compile(w, self.font)
- size += len(w.getAllData())
+ if not subtables:
+ return 0
+ # We need to make a copy here because compiling
+ # modifies the subtable (finalizing formats etc.)
+ table = self.buildLookup_(copy.deepcopy(subtables))
+ w = OTTableWriter()
+ table.compile(w, self.font)
+ size = len(w.getAllData())
return size
def build(self):
@@ -410,22 +409,23 @@ class ChainContextualBuilder(LookupBuilder):
if not ruleset.hasAnyGlyphClasses:
candidates[1] = [self.buildFormat1Subtable(ruleset, chaining)]
+ candidates_by_size = []
for i in [1, 2, 3]:
if candidates[i]:
try:
- self.getCompiledSize_(candidates[i])
- except Exception as e:
+ size = self.getCompiledSize_(candidates[i])
+ except OTLOffsetOverflowError as e:
log.warning(
"Contextual format %i at %s overflowed (%s)"
% (i, str(self.location), e)
)
- candidates[i] = None
+ else:
+ candidates_by_size.append((size, candidates[i]))
- candidates = [x for x in candidates if x is not None]
- if not candidates:
+ if not candidates_by_size:
raise OpenTypeLibError("All candidates overflowed", self.location)
- winner = min(candidates, key=self.getCompiledSize_)
+ _min_size, winner = min(candidates_by_size, key=lambda x: x[0])
subtables.extend(winner)
# If we are not chaining, lookup type will be automatically fixed by
@@ -774,7 +774,10 @@ class ChainContextSubstBuilder(ChainContextualBuilder):
if lookup is not None:
alts = lookup.getAlternateGlyphs()
for glyph, replacements in alts.items():
- result.setdefault(glyph, set()).update(replacements)
+ alts_for_glyph = result.setdefault(glyph, [])
+ alts_for_glyph.extend(
+ g for g in replacements if g not in alts_for_glyph
+ )
return result
def find_chainable_single_subst(self, mapping):
@@ -1238,7 +1241,7 @@ class SingleSubstBuilder(LookupBuilder):
return self.buildLookup_(subtables)
def getAlternateGlyphs(self):
- return {glyph: set([repl]) for glyph, repl in self.mapping.items()}
+ return {glyph: [repl] for glyph, repl in self.mapping.items()}
def add_subtable_break(self, location):
self.mapping[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
@@ -1567,19 +1570,6 @@ def buildAlternateSubstSubtable(mapping):
return self
-def _getLigatureKey(components):
- # Computes a key for ordering ligatures in a GSUB Type-4 lookup.
-
- # When building the OpenType lookup, we need to make sure that
- # the longest sequence of components is listed first, so we
- # use the negative length as the primary key for sorting.
- # To make buildLigatureSubstSubtable() deterministic, we use the
- # component sequence as the secondary key.
-
- # For example, this will sort (f,f,f) < (f,f,i) < (f,f) < (f,i) < (f,l).
- return (-len(components), components)
-
-
def buildLigatureSubstSubtable(mapping):
"""Builds a ligature substitution (GSUB4) subtable.
@@ -1613,7 +1603,7 @@ def buildLigatureSubstSubtable(mapping):
# with fontTools >= 3.1:
# self.ligatures = dict(mapping)
self.ligatures = {}
- for components in sorted(mapping.keys(), key=_getLigatureKey):
+ for components in sorted(mapping.keys(), key=self._getLigatureSortKey):
ligature = ot.Ligature()
ligature.Component = components[1:]
ligature.CompCount = len(ligature.Component) + 1
diff --git a/contrib/python/fonttools/fontTools/pens/hashPointPen.py b/contrib/python/fonttools/fontTools/pens/hashPointPen.py
index b82468ec9c..f15dcabbfd 100644
--- a/contrib/python/fonttools/fontTools/pens/hashPointPen.py
+++ b/contrib/python/fonttools/fontTools/pens/hashPointPen.py
@@ -31,6 +31,20 @@ class HashPointPen(AbstractPointPen):
> # The hash values are identical, the outline has not changed.
> # Compile the hinting code ...
> pass
+
+ If you want to compare a glyph from a source format which supports floating point
+ coordinates and transformations against a glyph from a format which has restrictions
+ on the precision of floats, e.g. UFO vs. TTF, you must use an appropriate rounding
+ function to make the values comparable. For TTF fonts with composites, this
+ construct can be used to make the transform values conform to F2Dot14:
+
+ > ttf_hash_pen = HashPointPen(ttf_glyph_width, ttFont.getGlyphSet())
+ > ttf_round_pen = RoundingPointPen(ttf_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
+ > ufo_hash_pen = HashPointPen(ufo_glyph.width, ufo)
+ > ttf_glyph.drawPoints(ttf_round_pen, ttFont["glyf"])
+ > ufo_round_pen = RoundingPointPen(ufo_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
+ > ufo_glyph.drawPoints(ufo_round_pen)
+ > assert ttf_hash_pen.hash == ufo_hash_pen.hash
"""
def __init__(self, glyphWidth=0, glyphSet=None):
diff --git a/contrib/python/fonttools/fontTools/pens/roundingPen.py b/contrib/python/fonttools/fontTools/pens/roundingPen.py
index 2a7c476c36..176bcc7a55 100644
--- a/contrib/python/fonttools/fontTools/pens/roundingPen.py
+++ b/contrib/python/fonttools/fontTools/pens/roundingPen.py
@@ -1,4 +1,4 @@
-from fontTools.misc.roundTools import otRound
+from fontTools.misc.roundTools import noRound, otRound
from fontTools.misc.transform import Transform
from fontTools.pens.filterPen import FilterPen, FilterPointPen
@@ -8,7 +8,9 @@ __all__ = ["RoundingPen", "RoundingPointPen"]
class RoundingPen(FilterPen):
"""
- Filter pen that rounds point coordinates and component XY offsets to integer.
+ Filter pen that rounds point coordinates and component XY offsets to integer. For
+ rounding the component transform values, a separate round function can be passed to
+ the pen.
>>> from fontTools.pens.recordingPen import RecordingPen
>>> recpen = RecordingPen()
@@ -28,9 +30,10 @@ class RoundingPen(FilterPen):
True
"""
- def __init__(self, outPen, roundFunc=otRound):
+ def __init__(self, outPen, roundFunc=otRound, transformRoundFunc=noRound):
super().__init__(outPen)
self.roundFunc = roundFunc
+ self.transformRoundFunc = transformRoundFunc
def moveTo(self, pt):
self._outPen.moveTo((self.roundFunc(pt[0]), self.roundFunc(pt[1])))
@@ -49,12 +52,16 @@ class RoundingPen(FilterPen):
)
def addComponent(self, glyphName, transformation):
+ xx, xy, yx, yy, dx, dy = transformation
self._outPen.addComponent(
glyphName,
Transform(
- *transformation[:4],
- self.roundFunc(transformation[4]),
- self.roundFunc(transformation[5]),
+ self.transformRoundFunc(xx),
+ self.transformRoundFunc(xy),
+ self.transformRoundFunc(yx),
+ self.transformRoundFunc(yy),
+ self.roundFunc(dx),
+ self.roundFunc(dy),
),
)
@@ -62,6 +69,8 @@ class RoundingPen(FilterPen):
class RoundingPointPen(FilterPointPen):
"""
Filter point pen that rounds point coordinates and component XY offsets to integer.
+ For rounding the component scale values, a separate round function can be passed to
+ the pen.
>>> from fontTools.pens.recordingPen import RecordingPointPen
>>> recpen = RecordingPointPen()
@@ -87,26 +96,35 @@ class RoundingPointPen(FilterPointPen):
True
"""
- def __init__(self, outPen, roundFunc=otRound):
+ def __init__(self, outPen, roundFunc=otRound, transformRoundFunc=noRound):
super().__init__(outPen)
self.roundFunc = roundFunc
+ self.transformRoundFunc = transformRoundFunc
- def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
+ def addPoint(
+ self, pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs
+ ):
self._outPen.addPoint(
(self.roundFunc(pt[0]), self.roundFunc(pt[1])),
segmentType=segmentType,
smooth=smooth,
name=name,
+ identifier=identifier,
**kwargs,
)
- def addComponent(self, baseGlyphName, transformation, **kwargs):
+ def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
+ xx, xy, yx, yy, dx, dy = transformation
self._outPen.addComponent(
- baseGlyphName,
- Transform(
- *transformation[:4],
- self.roundFunc(transformation[4]),
- self.roundFunc(transformation[5]),
+ baseGlyphName=baseGlyphName,
+ transformation=Transform(
+ self.transformRoundFunc(xx),
+ self.transformRoundFunc(xy),
+ self.transformRoundFunc(yx),
+ self.transformRoundFunc(yy),
+ self.roundFunc(dx),
+ self.roundFunc(dy),
),
+ identifier=identifier,
**kwargs,
)
diff --git a/contrib/python/fonttools/fontTools/pens/svgPathPen.py b/contrib/python/fonttools/fontTools/pens/svgPathPen.py
index 53b3683f2d..29d41a8029 100644
--- a/contrib/python/fonttools/fontTools/pens/svgPathPen.py
+++ b/contrib/python/fonttools/fontTools/pens/svgPathPen.py
@@ -220,13 +220,19 @@ def main(args=None):
"fonttools pens.svgPathPen", description="Generate SVG from text"
)
parser.add_argument("font", metavar="font.ttf", help="Font file.")
- parser.add_argument("text", metavar="text", help="Text string.")
+ parser.add_argument("text", metavar="text", nargs="?", help="Text string.")
parser.add_argument(
"-y",
metavar="<number>",
help="Face index into a collection to open. Zero based.",
)
parser.add_argument(
+ "--glyphs",
+ metavar="whitespace-separated list of glyph names",
+ type=str,
+ help="Glyphs to show. Exclusive with text option",
+ )
+ parser.add_argument(
"--variations",
metavar="AXIS=LOC",
default="",
@@ -241,6 +247,7 @@ def main(args=None):
font = TTFont(options.font, fontNumber=fontNumber)
text = options.text
+ glyphs = options.glyphs
location = {}
for tag_v in options.variations.split():
@@ -255,10 +262,17 @@ def main(args=None):
glyphset = font.getGlyphSet(location=location)
cmap = font["cmap"].getBestCmap()
+ if glyphs is not None and text is not None:
+ raise ValueError("Options --glyphs and --text are exclusive")
+
+ if glyphs is None:
+ glyphs = " ".join(cmap[ord(u)] for u in text)
+
+ glyphs = glyphs.split()
+
s = ""
width = 0
- for u in text:
- g = cmap[ord(u)]
+ for g in glyphs:
glyph = glyphset[g]
pen = SVGPathPen(glyphset)
diff --git a/contrib/python/fonttools/fontTools/subset/__init__.py b/contrib/python/fonttools/fontTools/subset/__init__.py
index 9b1758435c..250a07ef1a 100644
--- a/contrib/python/fonttools/fontTools/subset/__init__.py
+++ b/contrib/python/fonttools/fontTools/subset/__init__.py
@@ -3733,6 +3733,3 @@ __all__ = [
"parse_unicodes",
"main",
]
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/contrib/python/fonttools/fontTools/ttLib/tables/otTables.py b/contrib/python/fonttools/fontTools/ttLib/tables/otTables.py
index 262f8d4187..3505f42337 100644
--- a/contrib/python/fonttools/fontTools/ttLib/tables/otTables.py
+++ b/contrib/python/fonttools/fontTools/ttLib/tables/otTables.py
@@ -1123,6 +1123,35 @@ class LigatureSubst(FormatSwitchingBaseTable):
self.ligatures = ligatures
del self.Format # Don't need this anymore
+ @staticmethod
+ def _getLigatureSortKey(components):
+ # Computes a key for ordering ligatures in a GSUB Type-4 lookup.
+
+ # When building the OpenType lookup, we need to make sure that
+ # the longest sequence of components is listed first, so we
+ # use the negative length as the key for sorting.
+ # Note, we no longer need to worry about deterministic order because the
+ # ligature mapping `dict` remembers the insertion order, and this in
+ # turn depends on the order in which the ligatures are written in the FEA.
+ # Since python sort algorithm is stable, the ligatures of equal length
+ # will keep the relative order in which they appear in the feature file.
+ # For example, given the following ligatures (all starting with 'f' and
+ # thus belonging to the same LigatureSet):
+ #
+ # feature liga {
+ # sub f i by f_i;
+ # sub f f f by f_f_f;
+ # sub f f by f_f;
+ # sub f f i by f_f_i;
+ # } liga;
+ #
+ # this should sort to: f_f_f, f_f_i, f_i, f_f
+ # This is also what fea-rs does, see:
+ # https://github.com/adobe-type-tools/afdko/issues/1727
+ # https://github.com/fonttools/fonttools/issues/3428
+ # https://github.com/googlefonts/fontc/pull/680
+ return -len(components)
+
def preWrite(self, font):
self.Format = 1
ligatures = getattr(self, "ligatures", None)
@@ -1135,13 +1164,11 @@ class LigatureSubst(FormatSwitchingBaseTable):
# ligatures is map from components-sequence to lig-glyph
newLigatures = dict()
- for comps, lig in sorted(
- ligatures.items(), key=lambda item: (-len(item[0]), item[0])
- ):
+ for comps in sorted(ligatures.keys(), key=self._getLigatureSortKey):
ligature = Ligature()
ligature.Component = comps[1:]
ligature.CompCount = len(comps)
- ligature.LigGlyph = lig
+ ligature.LigGlyph = ligatures[comps]
newLigatures.setdefault(comps[0], []).append(ligature)
ligatures = newLigatures
diff --git a/contrib/python/fonttools/fontTools/ttLib/tables/sbixGlyph.py b/contrib/python/fonttools/fontTools/ttLib/tables/sbixGlyph.py
index fd687a1880..b744a2a3bc 100644
--- a/contrib/python/fonttools/fontTools/ttLib/tables/sbixGlyph.py
+++ b/contrib/python/fonttools/fontTools/ttLib/tables/sbixGlyph.py
@@ -54,6 +54,10 @@ class Glyph(object):
# pad with spaces
self.graphicType += " "[: (4 - len(self.graphicType))]
+ def is_reference_type(self):
+ """Returns True if this glyph is a reference to another glyph's image data."""
+ return self.graphicType == "dupe" or self.graphicType == "flip"
+
def decompile(self, ttFont):
self.glyphName = ttFont.getGlyphName(self.gid)
if self.rawdata is None:
@@ -71,7 +75,7 @@ class Glyph(object):
sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self
)
- if self.graphicType == "dupe":
+ if self.is_reference_type():
# this glyph is a reference to another glyph's image data
(gid,) = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:])
self.referenceGlyphName = ttFont.getGlyphName(gid)
@@ -94,7 +98,7 @@ class Glyph(object):
rawdata = b""
else:
rawdata = sstruct.pack(sbixGlyphHeaderFormat, self)
- if self.graphicType == "dupe":
+ if self.is_reference_type():
rawdata += struct.pack(">H", ttFont.getGlyphID(self.referenceGlyphName))
else:
assert self.imageData is not None
@@ -117,8 +121,8 @@ class Glyph(object):
originOffsetY=self.originOffsetY,
)
xmlWriter.newline()
- if self.graphicType == "dupe":
- # graphicType == "dupe" is a reference to another glyph id.
+ if self.is_reference_type():
+ # this glyph is a reference to another glyph id.
xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName)
else:
xmlWriter.begintag("hexdata")
@@ -131,7 +135,7 @@ class Glyph(object):
def fromXML(self, name, attrs, content, ttFont):
if name == "ref":
- # glyph is a "dupe", i.e. a reference to another glyph's image data.
+ # this glyph i.e. a reference to another glyph's image data.
# in this case imageData contains the glyph id of the reference glyph
# get glyph id from glyphname
glyphname = safeEval("'''" + attrs["glyphname"] + "'''")
diff --git a/contrib/python/fonttools/fontTools/varLib/__init__.py b/contrib/python/fonttools/fontTools/varLib/__init__.py
index 46834f6433..b9af6dacbf 100644
--- a/contrib/python/fonttools/fontTools/varLib/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/__init__.py
@@ -216,8 +216,6 @@ def _add_avar(font, axes, mappings, axisTags):
if mappings:
interesting = True
- hiddenAxes = [axis for axis in axes.values() if axis.hidden]
-
inputLocations = [
{
axes[name].tag: models.normalizeValue(v, vals_triples[axes[name].tag])
@@ -752,10 +750,14 @@ def _add_BASE(font, masterModel, master_ttfs, axisTags):
def _merge_OTL(font, model, master_fonts, axisTags):
+ otl_tags = ["GSUB", "GDEF", "GPOS"]
+ if not any(tag in font for tag in otl_tags):
+ return
+
log.info("Merging OpenType Layout tables")
merger = VariationMerger(model, axisTags, font)
- merger.mergeTables(font, master_fonts, ["GSUB", "GDEF", "GPOS"])
+ merger.mergeTables(font, master_fonts, otl_tags)
store = merger.store_builder.finish()
if not store:
return
diff --git a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
index d1cde0df7a..df55f0414d 100644
--- a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
@@ -614,7 +614,7 @@ def _instantiateGvarGlyph(
if optimize:
isComposite = glyf[glyphname].isComposite()
for var in tupleVarStore:
- var.optimize(coordinates, endPts, isComposite)
+ var.optimize(coordinates, endPts, isComposite=isComposite)
def instantiateGvarGlyph(varfont, glyphname, axisLimits, optimize=True):
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index 4d380b556c..35b91fddb1 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.47.2)
+VERSION(4.48.1)
LICENSE(MIT)
@@ -41,6 +41,7 @@ PY_SRCS(
fontTools/cu2qu/errors.py
fontTools/cu2qu/ufo.py
fontTools/designspaceLib/__init__.py
+ fontTools/designspaceLib/__main__.py
fontTools/designspaceLib/split.py
fontTools/designspaceLib/statNames.py
fontTools/designspaceLib/types.py