fonttools 4.60.2__cp311-cp311-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fontTools/__init__.py +8 -0
- fontTools/__main__.py +35 -0
- fontTools/afmLib.py +439 -0
- fontTools/agl.py +5233 -0
- fontTools/annotations.py +30 -0
- fontTools/cffLib/CFF2ToCFF.py +258 -0
- fontTools/cffLib/CFFToCFF2.py +305 -0
- fontTools/cffLib/__init__.py +3694 -0
- fontTools/cffLib/specializer.py +927 -0
- fontTools/cffLib/transforms.py +495 -0
- fontTools/cffLib/width.py +210 -0
- fontTools/colorLib/__init__.py +0 -0
- fontTools/colorLib/builder.py +664 -0
- fontTools/colorLib/errors.py +2 -0
- fontTools/colorLib/geometry.py +143 -0
- fontTools/colorLib/table_builder.py +223 -0
- fontTools/colorLib/unbuilder.py +81 -0
- fontTools/config/__init__.py +90 -0
- fontTools/cu2qu/__init__.py +15 -0
- fontTools/cu2qu/__main__.py +6 -0
- fontTools/cu2qu/benchmark.py +54 -0
- fontTools/cu2qu/cli.py +198 -0
- fontTools/cu2qu/cu2qu.c +15817 -0
- fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
- fontTools/cu2qu/cu2qu.py +563 -0
- fontTools/cu2qu/errors.py +77 -0
- fontTools/cu2qu/ufo.py +363 -0
- fontTools/designspaceLib/__init__.py +3343 -0
- fontTools/designspaceLib/__main__.py +6 -0
- fontTools/designspaceLib/split.py +475 -0
- fontTools/designspaceLib/statNames.py +260 -0
- fontTools/designspaceLib/types.py +147 -0
- fontTools/encodings/MacRoman.py +258 -0
- fontTools/encodings/StandardEncoding.py +258 -0
- fontTools/encodings/__init__.py +1 -0
- fontTools/encodings/codecs.py +135 -0
- fontTools/feaLib/__init__.py +4 -0
- fontTools/feaLib/__main__.py +78 -0
- fontTools/feaLib/ast.py +2143 -0
- fontTools/feaLib/builder.py +1814 -0
- fontTools/feaLib/error.py +22 -0
- fontTools/feaLib/lexer.c +17029 -0
- fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
- fontTools/feaLib/lexer.py +287 -0
- fontTools/feaLib/location.py +12 -0
- fontTools/feaLib/lookupDebugInfo.py +12 -0
- fontTools/feaLib/parser.py +2394 -0
- fontTools/feaLib/variableScalar.py +118 -0
- fontTools/fontBuilder.py +1014 -0
- fontTools/help.py +36 -0
- fontTools/merge/__init__.py +248 -0
- fontTools/merge/__main__.py +6 -0
- fontTools/merge/base.py +81 -0
- fontTools/merge/cmap.py +173 -0
- fontTools/merge/layout.py +526 -0
- fontTools/merge/options.py +85 -0
- fontTools/merge/tables.py +352 -0
- fontTools/merge/unicode.py +78 -0
- fontTools/merge/util.py +143 -0
- fontTools/misc/__init__.py +1 -0
- fontTools/misc/arrayTools.py +424 -0
- fontTools/misc/bezierTools.c +39731 -0
- fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
- fontTools/misc/bezierTools.py +1500 -0
- fontTools/misc/classifyTools.py +170 -0
- fontTools/misc/cliTools.py +53 -0
- fontTools/misc/configTools.py +349 -0
- fontTools/misc/cython.py +27 -0
- fontTools/misc/dictTools.py +83 -0
- fontTools/misc/eexec.py +119 -0
- fontTools/misc/encodingTools.py +72 -0
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/etree.py +456 -0
- fontTools/misc/filenames.py +245 -0
- fontTools/misc/filesystem/__init__.py +68 -0
- fontTools/misc/filesystem/_base.py +134 -0
- fontTools/misc/filesystem/_copy.py +45 -0
- fontTools/misc/filesystem/_errors.py +54 -0
- fontTools/misc/filesystem/_info.py +75 -0
- fontTools/misc/filesystem/_osfs.py +164 -0
- fontTools/misc/filesystem/_path.py +67 -0
- fontTools/misc/filesystem/_subfs.py +92 -0
- fontTools/misc/filesystem/_tempfs.py +34 -0
- fontTools/misc/filesystem/_tools.py +34 -0
- fontTools/misc/filesystem/_walk.py +55 -0
- fontTools/misc/filesystem/_zipfs.py +204 -0
- fontTools/misc/fixedTools.py +253 -0
- fontTools/misc/intTools.py +25 -0
- fontTools/misc/iterTools.py +12 -0
- fontTools/misc/lazyTools.py +42 -0
- fontTools/misc/loggingTools.py +543 -0
- fontTools/misc/macCreatorType.py +56 -0
- fontTools/misc/macRes.py +261 -0
- fontTools/misc/plistlib/__init__.py +681 -0
- fontTools/misc/plistlib/py.typed +0 -0
- fontTools/misc/psCharStrings.py +1511 -0
- fontTools/misc/psLib.py +398 -0
- fontTools/misc/psOperators.py +572 -0
- fontTools/misc/py23.py +96 -0
- fontTools/misc/roundTools.py +110 -0
- fontTools/misc/sstruct.py +227 -0
- fontTools/misc/symfont.py +242 -0
- fontTools/misc/testTools.py +233 -0
- fontTools/misc/textTools.py +156 -0
- fontTools/misc/timeTools.py +88 -0
- fontTools/misc/transform.py +516 -0
- fontTools/misc/treeTools.py +45 -0
- fontTools/misc/vector.py +147 -0
- fontTools/misc/visitor.py +158 -0
- fontTools/misc/xmlReader.py +188 -0
- fontTools/misc/xmlWriter.py +231 -0
- fontTools/mtiLib/__init__.py +1400 -0
- fontTools/mtiLib/__main__.py +5 -0
- fontTools/otlLib/__init__.py +1 -0
- fontTools/otlLib/builder.py +3465 -0
- fontTools/otlLib/error.py +11 -0
- fontTools/otlLib/maxContextCalc.py +96 -0
- fontTools/otlLib/optimize/__init__.py +53 -0
- fontTools/otlLib/optimize/__main__.py +6 -0
- fontTools/otlLib/optimize/gpos.py +439 -0
- fontTools/pens/__init__.py +1 -0
- fontTools/pens/areaPen.py +52 -0
- fontTools/pens/basePen.py +475 -0
- fontTools/pens/boundsPen.py +98 -0
- fontTools/pens/cairoPen.py +26 -0
- fontTools/pens/cocoaPen.py +26 -0
- fontTools/pens/cu2quPen.py +325 -0
- fontTools/pens/explicitClosingLinePen.py +101 -0
- fontTools/pens/filterPen.py +433 -0
- fontTools/pens/freetypePen.py +462 -0
- fontTools/pens/hashPointPen.py +89 -0
- fontTools/pens/momentsPen.c +13378 -0
- fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
- fontTools/pens/momentsPen.py +879 -0
- fontTools/pens/perimeterPen.py +69 -0
- fontTools/pens/pointInsidePen.py +192 -0
- fontTools/pens/pointPen.py +643 -0
- fontTools/pens/qtPen.py +29 -0
- fontTools/pens/qu2cuPen.py +105 -0
- fontTools/pens/quartzPen.py +43 -0
- fontTools/pens/recordingPen.py +335 -0
- fontTools/pens/reportLabPen.py +79 -0
- fontTools/pens/reverseContourPen.py +96 -0
- fontTools/pens/roundingPen.py +130 -0
- fontTools/pens/statisticsPen.py +312 -0
- fontTools/pens/svgPathPen.py +310 -0
- fontTools/pens/t2CharStringPen.py +88 -0
- fontTools/pens/teePen.py +55 -0
- fontTools/pens/transformPen.py +115 -0
- fontTools/pens/ttGlyphPen.py +335 -0
- fontTools/pens/wxPen.py +29 -0
- fontTools/qu2cu/__init__.py +15 -0
- fontTools/qu2cu/__main__.py +7 -0
- fontTools/qu2cu/benchmark.py +56 -0
- fontTools/qu2cu/cli.py +125 -0
- fontTools/qu2cu/qu2cu.c +16682 -0
- fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
- fontTools/qu2cu/qu2cu.py +405 -0
- fontTools/subset/__init__.py +4096 -0
- fontTools/subset/__main__.py +6 -0
- fontTools/subset/cff.py +184 -0
- fontTools/subset/svg.py +253 -0
- fontTools/subset/util.py +25 -0
- fontTools/svgLib/__init__.py +3 -0
- fontTools/svgLib/path/__init__.py +65 -0
- fontTools/svgLib/path/arc.py +154 -0
- fontTools/svgLib/path/parser.py +322 -0
- fontTools/svgLib/path/shapes.py +183 -0
- fontTools/t1Lib/__init__.py +648 -0
- fontTools/tfmLib.py +460 -0
- fontTools/ttLib/__init__.py +30 -0
- fontTools/ttLib/__main__.py +148 -0
- fontTools/ttLib/macUtils.py +54 -0
- fontTools/ttLib/removeOverlaps.py +395 -0
- fontTools/ttLib/reorderGlyphs.py +285 -0
- fontTools/ttLib/scaleUpem.py +436 -0
- fontTools/ttLib/sfnt.py +661 -0
- fontTools/ttLib/standardGlyphOrder.py +271 -0
- fontTools/ttLib/tables/B_A_S_E_.py +14 -0
- fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
- fontTools/ttLib/tables/C_B_D_T_.py +113 -0
- fontTools/ttLib/tables/C_B_L_C_.py +19 -0
- fontTools/ttLib/tables/C_F_F_.py +61 -0
- fontTools/ttLib/tables/C_F_F__2.py +26 -0
- fontTools/ttLib/tables/C_O_L_R_.py +165 -0
- fontTools/ttLib/tables/C_P_A_L_.py +305 -0
- fontTools/ttLib/tables/D_S_I_G_.py +158 -0
- fontTools/ttLib/tables/D__e_b_g.py +35 -0
- fontTools/ttLib/tables/DefaultTable.py +49 -0
- fontTools/ttLib/tables/E_B_D_T_.py +835 -0
- fontTools/ttLib/tables/E_B_L_C_.py +718 -0
- fontTools/ttLib/tables/F_F_T_M_.py +52 -0
- fontTools/ttLib/tables/F__e_a_t.py +149 -0
- fontTools/ttLib/tables/G_D_E_F_.py +13 -0
- fontTools/ttLib/tables/G_M_A_P_.py +148 -0
- fontTools/ttLib/tables/G_P_K_G_.py +133 -0
- fontTools/ttLib/tables/G_P_O_S_.py +14 -0
- fontTools/ttLib/tables/G_S_U_B_.py +13 -0
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/G__l_a_t.py +235 -0
- fontTools/ttLib/tables/G__l_o_c.py +85 -0
- fontTools/ttLib/tables/H_V_A_R_.py +13 -0
- fontTools/ttLib/tables/J_S_T_F_.py +13 -0
- fontTools/ttLib/tables/L_T_S_H_.py +58 -0
- fontTools/ttLib/tables/M_A_T_H_.py +13 -0
- fontTools/ttLib/tables/M_E_T_A_.py +352 -0
- fontTools/ttLib/tables/M_V_A_R_.py +13 -0
- fontTools/ttLib/tables/O_S_2f_2.py +752 -0
- fontTools/ttLib/tables/S_I_N_G_.py +99 -0
- fontTools/ttLib/tables/S_T_A_T_.py +15 -0
- fontTools/ttLib/tables/S_V_G_.py +223 -0
- fontTools/ttLib/tables/S__i_l_f.py +1040 -0
- fontTools/ttLib/tables/S__i_l_l.py +92 -0
- fontTools/ttLib/tables/T_S_I_B_.py +13 -0
- fontTools/ttLib/tables/T_S_I_C_.py +14 -0
- fontTools/ttLib/tables/T_S_I_D_.py +13 -0
- fontTools/ttLib/tables/T_S_I_J_.py +13 -0
- fontTools/ttLib/tables/T_S_I_P_.py +13 -0
- fontTools/ttLib/tables/T_S_I_S_.py +13 -0
- fontTools/ttLib/tables/T_S_I_V_.py +26 -0
- fontTools/ttLib/tables/T_S_I__0.py +70 -0
- fontTools/ttLib/tables/T_S_I__1.py +163 -0
- fontTools/ttLib/tables/T_S_I__2.py +17 -0
- fontTools/ttLib/tables/T_S_I__3.py +22 -0
- fontTools/ttLib/tables/T_S_I__5.py +60 -0
- fontTools/ttLib/tables/T_T_F_A_.py +14 -0
- fontTools/ttLib/tables/TupleVariation.py +884 -0
- fontTools/ttLib/tables/V_A_R_C_.py +12 -0
- fontTools/ttLib/tables/V_D_M_X_.py +249 -0
- fontTools/ttLib/tables/V_O_R_G_.py +165 -0
- fontTools/ttLib/tables/V_V_A_R_.py +13 -0
- fontTools/ttLib/tables/__init__.py +98 -0
- fontTools/ttLib/tables/_a_n_k_r.py +15 -0
- fontTools/ttLib/tables/_a_v_a_r.py +193 -0
- fontTools/ttLib/tables/_b_s_l_n.py +15 -0
- fontTools/ttLib/tables/_c_i_d_g.py +24 -0
- fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
- fontTools/ttLib/tables/_c_v_a_r.py +94 -0
- fontTools/ttLib/tables/_c_v_t.py +56 -0
- fontTools/ttLib/tables/_f_e_a_t.py +15 -0
- fontTools/ttLib/tables/_f_p_g_m.py +62 -0
- fontTools/ttLib/tables/_f_v_a_r.py +261 -0
- fontTools/ttLib/tables/_g_a_s_p.py +63 -0
- fontTools/ttLib/tables/_g_c_i_d.py +13 -0
- fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
- fontTools/ttLib/tables/_g_v_a_r.py +340 -0
- fontTools/ttLib/tables/_h_d_m_x.py +127 -0
- fontTools/ttLib/tables/_h_e_a_d.py +130 -0
- fontTools/ttLib/tables/_h_h_e_a.py +147 -0
- fontTools/ttLib/tables/_h_m_t_x.py +164 -0
- fontTools/ttLib/tables/_k_e_r_n.py +289 -0
- fontTools/ttLib/tables/_l_c_a_r.py +13 -0
- fontTools/ttLib/tables/_l_o_c_a.py +70 -0
- fontTools/ttLib/tables/_l_t_a_g.py +72 -0
- fontTools/ttLib/tables/_m_a_x_p.py +147 -0
- fontTools/ttLib/tables/_m_e_t_a.py +112 -0
- fontTools/ttLib/tables/_m_o_r_t.py +14 -0
- fontTools/ttLib/tables/_m_o_r_x.py +15 -0
- fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
- fontTools/ttLib/tables/_o_p_b_d.py +14 -0
- fontTools/ttLib/tables/_p_o_s_t.py +319 -0
- fontTools/ttLib/tables/_p_r_e_p.py +16 -0
- fontTools/ttLib/tables/_p_r_o_p.py +12 -0
- fontTools/ttLib/tables/_s_b_i_x.py +129 -0
- fontTools/ttLib/tables/_t_r_a_k.py +332 -0
- fontTools/ttLib/tables/_v_h_e_a.py +139 -0
- fontTools/ttLib/tables/_v_m_t_x.py +19 -0
- fontTools/ttLib/tables/asciiTable.py +20 -0
- fontTools/ttLib/tables/grUtils.py +92 -0
- fontTools/ttLib/tables/otBase.py +1458 -0
- fontTools/ttLib/tables/otConverters.py +2068 -0
- fontTools/ttLib/tables/otData.py +6400 -0
- fontTools/ttLib/tables/otTables.py +2703 -0
- fontTools/ttLib/tables/otTraverse.py +163 -0
- fontTools/ttLib/tables/sbixGlyph.py +149 -0
- fontTools/ttLib/tables/sbixStrike.py +177 -0
- fontTools/ttLib/tables/table_API_readme.txt +91 -0
- fontTools/ttLib/tables/ttProgram.py +594 -0
- fontTools/ttLib/ttCollection.py +125 -0
- fontTools/ttLib/ttFont.py +1148 -0
- fontTools/ttLib/ttGlyphSet.py +490 -0
- fontTools/ttLib/ttVisitor.py +32 -0
- fontTools/ttLib/woff2.py +1680 -0
- fontTools/ttx.py +479 -0
- fontTools/ufoLib/__init__.py +2575 -0
- fontTools/ufoLib/converters.py +407 -0
- fontTools/ufoLib/errors.py +30 -0
- fontTools/ufoLib/etree.py +6 -0
- fontTools/ufoLib/filenames.py +356 -0
- fontTools/ufoLib/glifLib.py +2120 -0
- fontTools/ufoLib/kerning.py +141 -0
- fontTools/ufoLib/plistlib.py +47 -0
- fontTools/ufoLib/pointPen.py +6 -0
- fontTools/ufoLib/utils.py +107 -0
- fontTools/ufoLib/validators.py +1208 -0
- fontTools/unicode.py +50 -0
- fontTools/unicodedata/Blocks.py +817 -0
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/OTTags.py +50 -0
- fontTools/unicodedata/ScriptExtensions.py +832 -0
- fontTools/unicodedata/Scripts.py +3639 -0
- fontTools/unicodedata/__init__.py +306 -0
- fontTools/varLib/__init__.py +1600 -0
- fontTools/varLib/__main__.py +6 -0
- fontTools/varLib/avar/__init__.py +0 -0
- fontTools/varLib/avar/__main__.py +72 -0
- fontTools/varLib/avar/build.py +79 -0
- fontTools/varLib/avar/map.py +108 -0
- fontTools/varLib/avar/plan.py +1004 -0
- fontTools/varLib/avar/unbuild.py +271 -0
- fontTools/varLib/avarPlanner.py +8 -0
- fontTools/varLib/builder.py +215 -0
- fontTools/varLib/cff.py +631 -0
- fontTools/varLib/errors.py +219 -0
- fontTools/varLib/featureVars.py +703 -0
- fontTools/varLib/hvar.py +113 -0
- fontTools/varLib/instancer/__init__.py +2052 -0
- fontTools/varLib/instancer/__main__.py +5 -0
- fontTools/varLib/instancer/featureVars.py +190 -0
- fontTools/varLib/instancer/names.py +388 -0
- fontTools/varLib/instancer/solver.py +309 -0
- fontTools/varLib/interpolatable.py +1209 -0
- fontTools/varLib/interpolatableHelpers.py +399 -0
- fontTools/varLib/interpolatablePlot.py +1269 -0
- fontTools/varLib/interpolatableTestContourOrder.py +82 -0
- fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
- fontTools/varLib/interpolate_layout.py +124 -0
- fontTools/varLib/iup.c +19815 -0
- fontTools/varLib/iup.cp311-win32.pyd +0 -0
- fontTools/varLib/iup.py +490 -0
- fontTools/varLib/merger.py +1717 -0
- fontTools/varLib/models.py +642 -0
- fontTools/varLib/multiVarStore.py +253 -0
- fontTools/varLib/mutator.py +529 -0
- fontTools/varLib/mvar.py +40 -0
- fontTools/varLib/plot.py +238 -0
- fontTools/varLib/stat.py +149 -0
- fontTools/varLib/varStore.py +739 -0
- fontTools/voltLib/__init__.py +5 -0
- fontTools/voltLib/__main__.py +206 -0
- fontTools/voltLib/ast.py +452 -0
- fontTools/voltLib/error.py +12 -0
- fontTools/voltLib/lexer.py +99 -0
- fontTools/voltLib/parser.py +664 -0
- fontTools/voltLib/voltToFea.py +911 -0
- fonttools-4.60.2.data/data/share/man/man1/ttx.1 +225 -0
- fonttools-4.60.2.dist-info/METADATA +2250 -0
- fonttools-4.60.2.dist-info/RECORD +353 -0
- fonttools-4.60.2.dist-info/WHEEL +5 -0
- fonttools-4.60.2.dist-info/entry_points.txt +5 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE +21 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE.external +388 -0
- fonttools-4.60.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fontTools.pens.basePen import AbstractPen, DecomposingPen
|
|
4
|
+
from fontTools.pens.pointPen import (
|
|
5
|
+
AbstractPointPen,
|
|
6
|
+
DecomposingPointPen,
|
|
7
|
+
ReverseFlipped,
|
|
8
|
+
)
|
|
9
|
+
from fontTools.pens.recordingPen import RecordingPen
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _PassThruComponentsMixin(object):
|
|
13
|
+
def addComponent(self, glyphName, transformation, **kwargs):
|
|
14
|
+
self._outPen.addComponent(glyphName, transformation, **kwargs)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FilterPen(_PassThruComponentsMixin, AbstractPen):
|
|
18
|
+
"""Base class for pens that apply some transformation to the coordinates
|
|
19
|
+
they receive and pass them to another pen.
|
|
20
|
+
|
|
21
|
+
You can override any of its methods. The default implementation does
|
|
22
|
+
nothing, but passes the commands unmodified to the other pen.
|
|
23
|
+
|
|
24
|
+
>>> from fontTools.pens.recordingPen import RecordingPen
|
|
25
|
+
>>> rec = RecordingPen()
|
|
26
|
+
>>> pen = FilterPen(rec)
|
|
27
|
+
>>> v = iter(rec.value)
|
|
28
|
+
|
|
29
|
+
>>> pen.moveTo((0, 0))
|
|
30
|
+
>>> next(v)
|
|
31
|
+
('moveTo', ((0, 0),))
|
|
32
|
+
|
|
33
|
+
>>> pen.lineTo((1, 1))
|
|
34
|
+
>>> next(v)
|
|
35
|
+
('lineTo', ((1, 1),))
|
|
36
|
+
|
|
37
|
+
>>> pen.curveTo((2, 2), (3, 3), (4, 4))
|
|
38
|
+
>>> next(v)
|
|
39
|
+
('curveTo', ((2, 2), (3, 3), (4, 4)))
|
|
40
|
+
|
|
41
|
+
>>> pen.qCurveTo((5, 5), (6, 6), (7, 7), (8, 8))
|
|
42
|
+
>>> next(v)
|
|
43
|
+
('qCurveTo', ((5, 5), (6, 6), (7, 7), (8, 8)))
|
|
44
|
+
|
|
45
|
+
>>> pen.closePath()
|
|
46
|
+
>>> next(v)
|
|
47
|
+
('closePath', ())
|
|
48
|
+
|
|
49
|
+
>>> pen.moveTo((9, 9))
|
|
50
|
+
>>> next(v)
|
|
51
|
+
('moveTo', ((9, 9),))
|
|
52
|
+
|
|
53
|
+
>>> pen.endPath()
|
|
54
|
+
>>> next(v)
|
|
55
|
+
('endPath', ())
|
|
56
|
+
|
|
57
|
+
>>> pen.addComponent('foo', (1, 0, 0, 1, 0, 0))
|
|
58
|
+
>>> next(v)
|
|
59
|
+
('addComponent', ('foo', (1, 0, 0, 1, 0, 0)))
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, outPen):
|
|
63
|
+
self._outPen = outPen
|
|
64
|
+
self.current_pt = None
|
|
65
|
+
|
|
66
|
+
def moveTo(self, pt):
|
|
67
|
+
self._outPen.moveTo(pt)
|
|
68
|
+
self.current_pt = pt
|
|
69
|
+
|
|
70
|
+
def lineTo(self, pt):
|
|
71
|
+
self._outPen.lineTo(pt)
|
|
72
|
+
self.current_pt = pt
|
|
73
|
+
|
|
74
|
+
def curveTo(self, *points):
|
|
75
|
+
self._outPen.curveTo(*points)
|
|
76
|
+
self.current_pt = points[-1]
|
|
77
|
+
|
|
78
|
+
def qCurveTo(self, *points):
|
|
79
|
+
self._outPen.qCurveTo(*points)
|
|
80
|
+
self.current_pt = points[-1]
|
|
81
|
+
|
|
82
|
+
def closePath(self):
|
|
83
|
+
self._outPen.closePath()
|
|
84
|
+
self.current_pt = None
|
|
85
|
+
|
|
86
|
+
def endPath(self):
|
|
87
|
+
self._outPen.endPath()
|
|
88
|
+
self.current_pt = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ContourFilterPen(_PassThruComponentsMixin, RecordingPen):
|
|
92
|
+
"""A "buffered" filter pen that accumulates contour data, passes
|
|
93
|
+
it through a ``filterContour`` method when the contour is closed or ended,
|
|
94
|
+
and finally draws the result with the output pen.
|
|
95
|
+
|
|
96
|
+
Components are passed through unchanged.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def __init__(self, outPen):
|
|
100
|
+
super(ContourFilterPen, self).__init__()
|
|
101
|
+
self._outPen = outPen
|
|
102
|
+
|
|
103
|
+
def closePath(self):
|
|
104
|
+
super(ContourFilterPen, self).closePath()
|
|
105
|
+
self._flushContour()
|
|
106
|
+
|
|
107
|
+
def endPath(self):
|
|
108
|
+
super(ContourFilterPen, self).endPath()
|
|
109
|
+
self._flushContour()
|
|
110
|
+
|
|
111
|
+
def _flushContour(self):
|
|
112
|
+
result = self.filterContour(self.value)
|
|
113
|
+
if result is not None:
|
|
114
|
+
self.value = result
|
|
115
|
+
self.replay(self._outPen)
|
|
116
|
+
self.value = []
|
|
117
|
+
|
|
118
|
+
def filterContour(self, contour):
|
|
119
|
+
"""Subclasses must override this to perform the filtering.
|
|
120
|
+
|
|
121
|
+
The contour is a list of pen (operator, operands) tuples.
|
|
122
|
+
Operators are strings corresponding to the AbstractPen methods:
|
|
123
|
+
"moveTo", "lineTo", "curveTo", "qCurveTo", "closePath" and
|
|
124
|
+
"endPath". The operands are the positional arguments that are
|
|
125
|
+
passed to each method.
|
|
126
|
+
|
|
127
|
+
If the method doesn't return a value (i.e. returns None), it's
|
|
128
|
+
assumed that the argument was modified in-place.
|
|
129
|
+
Otherwise, the return value is drawn with the output pen.
|
|
130
|
+
"""
|
|
131
|
+
return # or return contour
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
|
|
135
|
+
"""Baseclass for point pens that apply some transformation to the
|
|
136
|
+
coordinates they receive and pass them to another point pen.
|
|
137
|
+
|
|
138
|
+
You can override any of its methods. The default implementation does
|
|
139
|
+
nothing, but passes the commands unmodified to the other pen.
|
|
140
|
+
|
|
141
|
+
>>> from fontTools.pens.recordingPen import RecordingPointPen
|
|
142
|
+
>>> rec = RecordingPointPen()
|
|
143
|
+
>>> pen = FilterPointPen(rec)
|
|
144
|
+
>>> v = iter(rec.value)
|
|
145
|
+
>>> pen.beginPath(identifier="abc")
|
|
146
|
+
>>> next(v)
|
|
147
|
+
('beginPath', (), {'identifier': 'abc'})
|
|
148
|
+
>>> pen.addPoint((1, 2), "line", False)
|
|
149
|
+
>>> next(v)
|
|
150
|
+
('addPoint', ((1, 2), 'line', False, None), {})
|
|
151
|
+
>>> pen.addComponent("a", (2, 0, 0, 2, 10, -10), identifier="0001")
|
|
152
|
+
>>> next(v)
|
|
153
|
+
('addComponent', ('a', (2, 0, 0, 2, 10, -10)), {'identifier': '0001'})
|
|
154
|
+
>>> pen.endPath()
|
|
155
|
+
>>> next(v)
|
|
156
|
+
('endPath', (), {})
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def __init__(self, outPen):
|
|
160
|
+
self._outPen = outPen
|
|
161
|
+
|
|
162
|
+
def beginPath(self, identifier=None, **kwargs):
|
|
163
|
+
kwargs = dict(kwargs)
|
|
164
|
+
if identifier is not None:
|
|
165
|
+
kwargs["identifier"] = identifier
|
|
166
|
+
self._outPen.beginPath(**kwargs)
|
|
167
|
+
|
|
168
|
+
def endPath(self):
|
|
169
|
+
self._outPen.endPath()
|
|
170
|
+
|
|
171
|
+
def addPoint(
|
|
172
|
+
self,
|
|
173
|
+
pt,
|
|
174
|
+
segmentType=None,
|
|
175
|
+
smooth=False,
|
|
176
|
+
name=None,
|
|
177
|
+
identifier=None,
|
|
178
|
+
**kwargs,
|
|
179
|
+
):
|
|
180
|
+
kwargs = dict(kwargs)
|
|
181
|
+
if identifier is not None:
|
|
182
|
+
kwargs["identifier"] = identifier
|
|
183
|
+
self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class _DecomposingFilterMixinBase:
|
|
187
|
+
"""Base mixin class with common `addComponent` logic for decomposing filter pens."""
|
|
188
|
+
|
|
189
|
+
def addComponent(self, baseGlyphName, transformation, **kwargs):
|
|
190
|
+
# only decompose the component if it's included in the set
|
|
191
|
+
if self.include is None or baseGlyphName in self.include:
|
|
192
|
+
# if we're decomposing nested components, temporarily set include to None
|
|
193
|
+
include_bak = self.include
|
|
194
|
+
if self.decomposeNested and self.include:
|
|
195
|
+
self.include = None
|
|
196
|
+
try:
|
|
197
|
+
super().addComponent(baseGlyphName, transformation, **kwargs)
|
|
198
|
+
finally:
|
|
199
|
+
if self.include != include_bak:
|
|
200
|
+
self.include = include_bak
|
|
201
|
+
else:
|
|
202
|
+
_PassThruComponentsMixin.addComponent(
|
|
203
|
+
self, baseGlyphName, transformation, **kwargs
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class _DecomposingFilterPenMixin(_DecomposingFilterMixinBase):
|
|
208
|
+
"""Mixin class that decomposes components as regular contours for segment pens.
|
|
209
|
+
|
|
210
|
+
Used by DecomposingFilterPen.
|
|
211
|
+
|
|
212
|
+
Takes two required parameters, another segment pen 'outPen' to draw
|
|
213
|
+
with, and a 'glyphSet' dict of drawable glyph objects to draw components from.
|
|
214
|
+
|
|
215
|
+
The 'skipMissingComponents' and 'reverseFlipped' optional arguments work the
|
|
216
|
+
same as in the DecomposingPen. reverseFlipped is bool only (True/False).
|
|
217
|
+
|
|
218
|
+
In addition, the decomposing filter pens also take the following two options:
|
|
219
|
+
|
|
220
|
+
'include' is an optional set of component base glyph names to consider for
|
|
221
|
+
decomposition; the default include=None means decompose all components no matter
|
|
222
|
+
the base glyph name).
|
|
223
|
+
|
|
224
|
+
'decomposeNested' (bool) controls whether to recurse decomposition into nested
|
|
225
|
+
components of components (this only matters when 'include' was also provided);
|
|
226
|
+
if False, only decompose top-level components included in the set, but not
|
|
227
|
+
also their children.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# raises MissingComponentError if base glyph is not found in glyphSet
|
|
231
|
+
skipMissingComponents = False
|
|
232
|
+
|
|
233
|
+
def __init__(
|
|
234
|
+
self,
|
|
235
|
+
outPen,
|
|
236
|
+
glyphSet,
|
|
237
|
+
skipMissingComponents=None,
|
|
238
|
+
reverseFlipped: bool = False,
|
|
239
|
+
include: set[str] | None = None,
|
|
240
|
+
decomposeNested: bool = True,
|
|
241
|
+
**kwargs,
|
|
242
|
+
):
|
|
243
|
+
assert isinstance(
|
|
244
|
+
reverseFlipped, bool
|
|
245
|
+
), f"Expected bool, got {type(reverseFlipped).__name__}"
|
|
246
|
+
super().__init__(
|
|
247
|
+
outPen=outPen,
|
|
248
|
+
glyphSet=glyphSet,
|
|
249
|
+
skipMissingComponents=skipMissingComponents,
|
|
250
|
+
reverseFlipped=reverseFlipped,
|
|
251
|
+
**kwargs,
|
|
252
|
+
)
|
|
253
|
+
self.include = include
|
|
254
|
+
self.decomposeNested = decomposeNested
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class _DecomposingFilterPointPenMixin(_DecomposingFilterMixinBase):
|
|
258
|
+
"""Mixin class that decomposes components as regular contours for point pens.
|
|
259
|
+
|
|
260
|
+
Takes two required parameters, another point pen 'outPen' to draw
|
|
261
|
+
with, and a 'glyphSet' dict of drawable glyph objects to draw components from.
|
|
262
|
+
|
|
263
|
+
The 'skipMissingComponents' and 'reverseFlipped' optional arguments work the
|
|
264
|
+
same as in the DecomposingPointPen. reverseFlipped accepts bool | ReverseFlipped
|
|
265
|
+
(see DecomposingPointPen).
|
|
266
|
+
|
|
267
|
+
In addition, the decomposing filter pens also take the following two options:
|
|
268
|
+
|
|
269
|
+
'include' is an optional set of component base glyph names to consider for
|
|
270
|
+
decomposition; the default include=None means decompose all components no matter
|
|
271
|
+
the base glyph name).
|
|
272
|
+
|
|
273
|
+
'decomposeNested' (bool) controls whether to recurse decomposition into nested
|
|
274
|
+
components of components (this only matters when 'include' was also provided);
|
|
275
|
+
if False, only decompose top-level components included in the set, but not
|
|
276
|
+
also their children.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
# raises MissingComponentError if base glyph is not found in glyphSet
|
|
280
|
+
skipMissingComponents = False
|
|
281
|
+
|
|
282
|
+
def __init__(
|
|
283
|
+
self,
|
|
284
|
+
outPen,
|
|
285
|
+
glyphSet,
|
|
286
|
+
skipMissingComponents=None,
|
|
287
|
+
reverseFlipped: bool | ReverseFlipped = False,
|
|
288
|
+
include: set[str] | None = None,
|
|
289
|
+
decomposeNested: bool = True,
|
|
290
|
+
**kwargs,
|
|
291
|
+
):
|
|
292
|
+
super().__init__(
|
|
293
|
+
outPen=outPen,
|
|
294
|
+
glyphSet=glyphSet,
|
|
295
|
+
skipMissingComponents=skipMissingComponents,
|
|
296
|
+
reverseFlipped=reverseFlipped,
|
|
297
|
+
**kwargs,
|
|
298
|
+
)
|
|
299
|
+
self.include = include
|
|
300
|
+
self.decomposeNested = decomposeNested
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class DecomposingFilterPen(_DecomposingFilterPenMixin, DecomposingPen, FilterPen):
|
|
304
|
+
"""Filter pen that draws components as regular contours."""
|
|
305
|
+
|
|
306
|
+
pass
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class DecomposingFilterPointPen(
|
|
310
|
+
_DecomposingFilterPointPenMixin, DecomposingPointPen, FilterPointPen
|
|
311
|
+
):
|
|
312
|
+
"""Filter point pen that draws components as regular contours."""
|
|
313
|
+
|
|
314
|
+
pass
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class ContourFilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
|
|
318
|
+
"""A "buffered" filter point pen that accumulates contour data, passes
|
|
319
|
+
it through a ``filterContour`` method when the contour is closed or ended,
|
|
320
|
+
and finally draws the result with the output point pen.
|
|
321
|
+
|
|
322
|
+
Components are passed through unchanged.
|
|
323
|
+
|
|
324
|
+
The ``filterContour`` method can modify the contour in-place (return None)
|
|
325
|
+
or return a new contour to replace it.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
def __init__(self, outPen):
|
|
329
|
+
self._outPen = outPen
|
|
330
|
+
self.currentContour = None
|
|
331
|
+
self.currentContourKwargs = None
|
|
332
|
+
|
|
333
|
+
def beginPath(self, identifier=None, **kwargs):
|
|
334
|
+
if self.currentContour is not None:
|
|
335
|
+
raise ValueError("Path already begun")
|
|
336
|
+
kwargs = dict(kwargs)
|
|
337
|
+
if identifier is not None:
|
|
338
|
+
kwargs["identifier"] = identifier
|
|
339
|
+
self.currentContour = []
|
|
340
|
+
self.currentContourKwargs = kwargs
|
|
341
|
+
|
|
342
|
+
def endPath(self):
|
|
343
|
+
if self.currentContour is None:
|
|
344
|
+
raise ValueError("Path not begun")
|
|
345
|
+
self._flushContour()
|
|
346
|
+
self.currentContour = None
|
|
347
|
+
self.currentContourKwargs = None
|
|
348
|
+
|
|
349
|
+
def _flushContour(self):
|
|
350
|
+
"""Flush the current contour to the output pen."""
|
|
351
|
+
result = self.filterContour(self.currentContour)
|
|
352
|
+
if result is not None:
|
|
353
|
+
self.currentContour = result
|
|
354
|
+
|
|
355
|
+
# Draw the filtered contour
|
|
356
|
+
self._outPen.beginPath(**self.currentContourKwargs)
|
|
357
|
+
for pt, segmentType, smooth, name, kwargs in self.currentContour:
|
|
358
|
+
self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)
|
|
359
|
+
self._outPen.endPath()
|
|
360
|
+
|
|
361
|
+
def filterContour(self, contour):
|
|
362
|
+
"""Subclasses must override this to perform the filtering.
|
|
363
|
+
|
|
364
|
+
The contour is a list of (pt, segmentType, smooth, name, kwargs) tuples.
|
|
365
|
+
If the method doesn't return a value (i.e. returns None), it's
|
|
366
|
+
assumed that the contour was modified in-place.
|
|
367
|
+
Otherwise, the return value replaces the original contour.
|
|
368
|
+
"""
|
|
369
|
+
return # or return contour
|
|
370
|
+
|
|
371
|
+
def addPoint(
|
|
372
|
+
self,
|
|
373
|
+
pt,
|
|
374
|
+
segmentType=None,
|
|
375
|
+
smooth=False,
|
|
376
|
+
name=None,
|
|
377
|
+
identifier=None,
|
|
378
|
+
**kwargs,
|
|
379
|
+
):
|
|
380
|
+
if self.currentContour is None:
|
|
381
|
+
raise ValueError("Path not begun")
|
|
382
|
+
kwargs = dict(kwargs)
|
|
383
|
+
if identifier is not None:
|
|
384
|
+
kwargs["identifier"] = identifier
|
|
385
|
+
self.currentContour.append((pt, segmentType, smooth, name, kwargs))
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class OnCurveFirstPointPen(ContourFilterPointPen):
|
|
389
|
+
"""Filter point pen that ensures closed contours start with an on-curve point.
|
|
390
|
+
|
|
391
|
+
If a closed contour starts with an off-curve point (segmentType=None), it rotates
|
|
392
|
+
the points list so that the first on-curve point (segmentType != None) becomes
|
|
393
|
+
the start point. Open contours and contours already starting with on-curve points
|
|
394
|
+
are passed through unchanged.
|
|
395
|
+
|
|
396
|
+
>>> from fontTools.pens.recordingPen import RecordingPointPen
|
|
397
|
+
>>> rec = RecordingPointPen()
|
|
398
|
+
>>> pen = OnCurveFirstPointPen(rec)
|
|
399
|
+
>>> # Closed contour starting with off-curve - will be rotated
|
|
400
|
+
>>> pen.beginPath()
|
|
401
|
+
>>> pen.addPoint((0, 0), None) # off-curve
|
|
402
|
+
>>> pen.addPoint((100, 100), "line") # on-curve - will become start
|
|
403
|
+
>>> pen.addPoint((200, 0), None) # off-curve
|
|
404
|
+
>>> pen.addPoint((300, 100), "curve") # on-curve
|
|
405
|
+
>>> pen.endPath()
|
|
406
|
+
>>> # The contour should now start with (100, 100) "line"
|
|
407
|
+
>>> rec.value[0]
|
|
408
|
+
('beginPath', (), {})
|
|
409
|
+
>>> rec.value[1]
|
|
410
|
+
('addPoint', ((100, 100), 'line', False, None), {})
|
|
411
|
+
>>> rec.value[2]
|
|
412
|
+
('addPoint', ((200, 0), None, False, None), {})
|
|
413
|
+
>>> rec.value[3]
|
|
414
|
+
('addPoint', ((300, 100), 'curve', False, None), {})
|
|
415
|
+
>>> rec.value[4]
|
|
416
|
+
('addPoint', ((0, 0), None, False, None), {})
|
|
417
|
+
"""
|
|
418
|
+
|
|
419
|
+
def filterContour(self, contour):
|
|
420
|
+
"""Rotate closed contour to start with first on-curve point if needed."""
|
|
421
|
+
if not contour:
|
|
422
|
+
return
|
|
423
|
+
|
|
424
|
+
# Check if it's a closed contour (no "move" segmentType)
|
|
425
|
+
is_closed = contour[0][1] != "move"
|
|
426
|
+
|
|
427
|
+
if is_closed and contour[0][1] is None:
|
|
428
|
+
# Closed contour starting with off-curve - need to rotate
|
|
429
|
+
# Find the first on-curve point
|
|
430
|
+
for i, (pt, segmentType, smooth, name, kwargs) in enumerate(contour):
|
|
431
|
+
if segmentType is not None:
|
|
432
|
+
# Rotate the points list so it starts with the first on-curve point
|
|
433
|
+
return contour[i:] + contour[:i]
|