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,490 @@
|
|
|
1
|
+
"""GlyphSets returned by a TTFont."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from copy import copy, deepcopy
|
|
7
|
+
from types import SimpleNamespace
|
|
8
|
+
from fontTools.misc.vector import Vector
|
|
9
|
+
from fontTools.misc.fixedTools import otRound, fixedToFloat as fi2fl
|
|
10
|
+
from fontTools.misc.loggingTools import deprecateFunction
|
|
11
|
+
from fontTools.misc.transform import Transform, DecomposedTransform
|
|
12
|
+
from fontTools.pens.transformPen import TransformPen, TransformPointPen
|
|
13
|
+
from fontTools.pens.recordingPen import (
|
|
14
|
+
DecomposingRecordingPen,
|
|
15
|
+
lerpRecordings,
|
|
16
|
+
replayRecording,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _TTGlyphSet(Mapping):
|
|
21
|
+
"""Generic dict-like GlyphSet class that pulls metrics from hmtx and
|
|
22
|
+
glyph shape from TrueType or CFF.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, font, location, glyphsMapping, *, recalcBounds=True):
|
|
26
|
+
self.recalcBounds = recalcBounds
|
|
27
|
+
self.font = font
|
|
28
|
+
self.defaultLocationNormalized = (
|
|
29
|
+
{axis.axisTag: 0 for axis in self.font["fvar"].axes}
|
|
30
|
+
if "fvar" in self.font
|
|
31
|
+
else {}
|
|
32
|
+
)
|
|
33
|
+
self.location = location if location is not None else {}
|
|
34
|
+
self.rawLocation = {} # VarComponent-only location
|
|
35
|
+
self.originalLocation = location if location is not None else {}
|
|
36
|
+
self.depth = 0
|
|
37
|
+
self.locationStack = []
|
|
38
|
+
self.rawLocationStack = []
|
|
39
|
+
self.glyphsMapping = glyphsMapping
|
|
40
|
+
self.hMetrics = font["hmtx"].metrics
|
|
41
|
+
self.vMetrics = getattr(font.get("vmtx"), "metrics", None)
|
|
42
|
+
self.hvarTable = None
|
|
43
|
+
if location:
|
|
44
|
+
from fontTools.varLib.varStore import VarStoreInstancer
|
|
45
|
+
|
|
46
|
+
self.hvarTable = getattr(font.get("HVAR"), "table", None)
|
|
47
|
+
if self.hvarTable is not None:
|
|
48
|
+
self.hvarInstancer = VarStoreInstancer(
|
|
49
|
+
self.hvarTable.VarStore, font["fvar"].axes, location
|
|
50
|
+
)
|
|
51
|
+
# TODO VVAR, VORG
|
|
52
|
+
|
|
53
|
+
@contextmanager
|
|
54
|
+
def pushLocation(self, location, reset: bool):
|
|
55
|
+
self.locationStack.append(self.location)
|
|
56
|
+
self.rawLocationStack.append(self.rawLocation)
|
|
57
|
+
if reset:
|
|
58
|
+
self.location = self.originalLocation.copy()
|
|
59
|
+
self.rawLocation = self.defaultLocationNormalized.copy()
|
|
60
|
+
else:
|
|
61
|
+
self.location = self.location.copy()
|
|
62
|
+
self.rawLocation = {}
|
|
63
|
+
self.location.update(location)
|
|
64
|
+
self.rawLocation.update(location)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
yield None
|
|
68
|
+
finally:
|
|
69
|
+
self.location = self.locationStack.pop()
|
|
70
|
+
self.rawLocation = self.rawLocationStack.pop()
|
|
71
|
+
|
|
72
|
+
@contextmanager
|
|
73
|
+
def pushDepth(self):
|
|
74
|
+
try:
|
|
75
|
+
depth = self.depth
|
|
76
|
+
self.depth += 1
|
|
77
|
+
yield depth
|
|
78
|
+
finally:
|
|
79
|
+
self.depth -= 1
|
|
80
|
+
|
|
81
|
+
def __contains__(self, glyphName):
|
|
82
|
+
return glyphName in self.glyphsMapping
|
|
83
|
+
|
|
84
|
+
def __iter__(self):
|
|
85
|
+
return iter(self.glyphsMapping.keys())
|
|
86
|
+
|
|
87
|
+
def __len__(self):
|
|
88
|
+
return len(self.glyphsMapping)
|
|
89
|
+
|
|
90
|
+
@deprecateFunction(
|
|
91
|
+
"use 'glyphName in glyphSet' instead", category=DeprecationWarning
|
|
92
|
+
)
|
|
93
|
+
def has_key(self, glyphName):
|
|
94
|
+
return glyphName in self.glyphsMapping
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class _TTGlyphSetGlyf(_TTGlyphSet):
|
|
98
|
+
def __init__(self, font, location, recalcBounds=True):
|
|
99
|
+
self.glyfTable = font["glyf"]
|
|
100
|
+
super().__init__(font, location, self.glyfTable, recalcBounds=recalcBounds)
|
|
101
|
+
self.gvarTable = font.get("gvar")
|
|
102
|
+
|
|
103
|
+
def __getitem__(self, glyphName):
|
|
104
|
+
return _TTGlyphGlyf(self, glyphName, recalcBounds=self.recalcBounds)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class _TTGlyphSetCFF(_TTGlyphSet):
|
|
108
|
+
def __init__(self, font, location):
|
|
109
|
+
tableTag = "CFF2" if "CFF2" in font else "CFF "
|
|
110
|
+
self.charStrings = list(font[tableTag].cff.values())[0].CharStrings
|
|
111
|
+
super().__init__(font, location, self.charStrings)
|
|
112
|
+
self.setLocation(location)
|
|
113
|
+
|
|
114
|
+
def __getitem__(self, glyphName):
|
|
115
|
+
return _TTGlyphCFF(self, glyphName)
|
|
116
|
+
|
|
117
|
+
def setLocation(self, location):
|
|
118
|
+
self.blender = None
|
|
119
|
+
if location:
|
|
120
|
+
# TODO Optimize by using instancer.setLocation()
|
|
121
|
+
|
|
122
|
+
from fontTools.varLib.varStore import VarStoreInstancer
|
|
123
|
+
|
|
124
|
+
varStore = getattr(self.charStrings, "varStore", None)
|
|
125
|
+
if varStore is not None:
|
|
126
|
+
instancer = VarStoreInstancer(
|
|
127
|
+
varStore.otVarStore, self.font["fvar"].axes, location
|
|
128
|
+
)
|
|
129
|
+
self.blender = instancer.interpolateFromDeltas
|
|
130
|
+
else:
|
|
131
|
+
self.blender = None
|
|
132
|
+
|
|
133
|
+
@contextmanager
|
|
134
|
+
def pushLocation(self, location, reset: bool):
|
|
135
|
+
self.setLocation(location)
|
|
136
|
+
with _TTGlyphSet.pushLocation(self, location, reset) as value:
|
|
137
|
+
try:
|
|
138
|
+
yield value
|
|
139
|
+
finally:
|
|
140
|
+
self.setLocation(self.location)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class _TTGlyphSetVARC(_TTGlyphSet):
|
|
144
|
+
def __init__(self, font, location, glyphSet):
|
|
145
|
+
self.glyphSet = glyphSet
|
|
146
|
+
super().__init__(font, location, glyphSet)
|
|
147
|
+
self.varcTable = font["VARC"].table
|
|
148
|
+
|
|
149
|
+
def __getitem__(self, glyphName):
|
|
150
|
+
varc = self.varcTable
|
|
151
|
+
if glyphName not in varc.Coverage.glyphs:
|
|
152
|
+
return self.glyphSet[glyphName]
|
|
153
|
+
return _TTGlyphVARC(self, glyphName)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class _TTGlyph(ABC):
|
|
157
|
+
"""Glyph object that supports the Pen protocol, meaning that it has
|
|
158
|
+
.draw() and .drawPoints() methods that take a pen object as their only
|
|
159
|
+
argument. Additionally there are 'width' and 'lsb' attributes, read from
|
|
160
|
+
the 'hmtx' table.
|
|
161
|
+
|
|
162
|
+
If the font contains a 'vmtx' table, there will also be 'height' and 'tsb'
|
|
163
|
+
attributes.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
def __init__(self, glyphSet, glyphName, *, recalcBounds=True):
|
|
167
|
+
self.glyphSet = glyphSet
|
|
168
|
+
self.name = glyphName
|
|
169
|
+
self.recalcBounds = recalcBounds
|
|
170
|
+
self.width, self.lsb = glyphSet.hMetrics[glyphName]
|
|
171
|
+
if glyphSet.vMetrics is not None:
|
|
172
|
+
self.height, self.tsb = glyphSet.vMetrics[glyphName]
|
|
173
|
+
else:
|
|
174
|
+
self.height, self.tsb = None, None
|
|
175
|
+
if glyphSet.location and glyphSet.hvarTable is not None:
|
|
176
|
+
varidx = (
|
|
177
|
+
glyphSet.font.getGlyphID(glyphName)
|
|
178
|
+
if glyphSet.hvarTable.AdvWidthMap is None
|
|
179
|
+
else glyphSet.hvarTable.AdvWidthMap.mapping[glyphName]
|
|
180
|
+
)
|
|
181
|
+
self.width += glyphSet.hvarInstancer[varidx]
|
|
182
|
+
# TODO: VVAR/VORG
|
|
183
|
+
|
|
184
|
+
@abstractmethod
|
|
185
|
+
def draw(self, pen):
|
|
186
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
|
|
187
|
+
how that works.
|
|
188
|
+
"""
|
|
189
|
+
raise NotImplementedError
|
|
190
|
+
|
|
191
|
+
def drawPoints(self, pen):
|
|
192
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.pointPen for details
|
|
193
|
+
how that works.
|
|
194
|
+
"""
|
|
195
|
+
from fontTools.pens.pointPen import SegmentToPointPen
|
|
196
|
+
|
|
197
|
+
self.draw(SegmentToPointPen(pen))
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class _TTGlyphGlyf(_TTGlyph):
|
|
201
|
+
def draw(self, pen):
|
|
202
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
|
|
203
|
+
how that works.
|
|
204
|
+
"""
|
|
205
|
+
glyph, offset = self._getGlyphAndOffset()
|
|
206
|
+
|
|
207
|
+
with self.glyphSet.pushDepth() as depth:
|
|
208
|
+
if depth:
|
|
209
|
+
offset = 0 # Offset should only apply at top-level
|
|
210
|
+
|
|
211
|
+
glyph.draw(pen, self.glyphSet.glyfTable, offset)
|
|
212
|
+
|
|
213
|
+
def drawPoints(self, pen):
|
|
214
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.pointPen for details
|
|
215
|
+
how that works.
|
|
216
|
+
"""
|
|
217
|
+
glyph, offset = self._getGlyphAndOffset()
|
|
218
|
+
|
|
219
|
+
with self.glyphSet.pushDepth() as depth:
|
|
220
|
+
if depth:
|
|
221
|
+
offset = 0 # Offset should only apply at top-level
|
|
222
|
+
|
|
223
|
+
glyph.drawPoints(pen, self.glyphSet.glyfTable, offset)
|
|
224
|
+
|
|
225
|
+
def _getGlyphAndOffset(self):
|
|
226
|
+
if self.glyphSet.location and self.glyphSet.gvarTable is not None:
|
|
227
|
+
glyph = self._getGlyphInstance()
|
|
228
|
+
else:
|
|
229
|
+
glyph = self.glyphSet.glyfTable[self.name]
|
|
230
|
+
|
|
231
|
+
offset = self.lsb - glyph.xMin if hasattr(glyph, "xMin") else 0
|
|
232
|
+
return glyph, offset
|
|
233
|
+
|
|
234
|
+
def _getGlyphInstance(self):
|
|
235
|
+
from fontTools.varLib.iup import iup_delta
|
|
236
|
+
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
|
|
237
|
+
from fontTools.varLib.models import supportScalar
|
|
238
|
+
|
|
239
|
+
glyphSet = self.glyphSet
|
|
240
|
+
glyfTable = glyphSet.glyfTable
|
|
241
|
+
variations = glyphSet.gvarTable.variations[self.name]
|
|
242
|
+
hMetrics = glyphSet.hMetrics
|
|
243
|
+
vMetrics = glyphSet.vMetrics
|
|
244
|
+
coordinates, _ = glyfTable._getCoordinatesAndControls(
|
|
245
|
+
self.name, hMetrics, vMetrics
|
|
246
|
+
)
|
|
247
|
+
origCoords, endPts = None, None
|
|
248
|
+
for var in variations:
|
|
249
|
+
scalar = supportScalar(glyphSet.location, var.axes)
|
|
250
|
+
if not scalar:
|
|
251
|
+
continue
|
|
252
|
+
delta = var.coordinates
|
|
253
|
+
if None in delta:
|
|
254
|
+
if origCoords is None:
|
|
255
|
+
origCoords, control = glyfTable._getCoordinatesAndControls(
|
|
256
|
+
self.name, hMetrics, vMetrics
|
|
257
|
+
)
|
|
258
|
+
endPts = (
|
|
259
|
+
control[1] if control[0] >= 1 else list(range(len(control[1])))
|
|
260
|
+
)
|
|
261
|
+
delta = iup_delta(delta, origCoords, endPts)
|
|
262
|
+
coordinates += GlyphCoordinates(delta) * scalar
|
|
263
|
+
|
|
264
|
+
glyph = copy(glyfTable[self.name]) # Shallow copy
|
|
265
|
+
width, lsb, height, tsb = _setCoordinates(
|
|
266
|
+
glyph, coordinates, glyfTable, recalcBounds=self.recalcBounds
|
|
267
|
+
)
|
|
268
|
+
self.lsb = lsb
|
|
269
|
+
self.tsb = tsb
|
|
270
|
+
if glyphSet.hvarTable is None:
|
|
271
|
+
# no HVAR: let's set metrics from the phantom points
|
|
272
|
+
self.width = width
|
|
273
|
+
self.height = height
|
|
274
|
+
return glyph
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class _TTGlyphCFF(_TTGlyph):
|
|
278
|
+
def draw(self, pen):
|
|
279
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
|
|
280
|
+
how that works.
|
|
281
|
+
"""
|
|
282
|
+
self.glyphSet.charStrings[self.name].draw(pen, self.glyphSet.blender)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _evaluateCondition(condition, fvarAxes, location, instancer):
|
|
286
|
+
if condition.Format == 1:
|
|
287
|
+
# ConditionAxisRange
|
|
288
|
+
axisIndex = condition.AxisIndex
|
|
289
|
+
axisTag = fvarAxes[axisIndex].axisTag
|
|
290
|
+
axisValue = location.get(axisTag, 0)
|
|
291
|
+
minValue = condition.FilterRangeMinValue
|
|
292
|
+
maxValue = condition.FilterRangeMaxValue
|
|
293
|
+
return minValue <= axisValue <= maxValue
|
|
294
|
+
elif condition.Format == 2:
|
|
295
|
+
# ConditionValue
|
|
296
|
+
value = condition.DefaultValue
|
|
297
|
+
value += instancer[condition.VarIdx][0]
|
|
298
|
+
return value > 0
|
|
299
|
+
elif condition.Format == 3:
|
|
300
|
+
# ConditionAnd
|
|
301
|
+
for subcondition in condition.ConditionTable:
|
|
302
|
+
if not _evaluateCondition(subcondition, fvarAxes, location, instancer):
|
|
303
|
+
return False
|
|
304
|
+
return True
|
|
305
|
+
elif condition.Format == 4:
|
|
306
|
+
# ConditionOr
|
|
307
|
+
for subcondition in condition.ConditionTable:
|
|
308
|
+
if _evaluateCondition(subcondition, fvarAxes, location, instancer):
|
|
309
|
+
return True
|
|
310
|
+
return False
|
|
311
|
+
elif condition.Format == 5:
|
|
312
|
+
# ConditionNegate
|
|
313
|
+
return not _evaluateCondition(
|
|
314
|
+
condition.conditionTable, fvarAxes, location, instancer
|
|
315
|
+
)
|
|
316
|
+
else:
|
|
317
|
+
return False # Unkonwn condition format
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class _TTGlyphVARC(_TTGlyph):
|
|
321
|
+
def _draw(self, pen, isPointPen):
|
|
322
|
+
"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
|
|
323
|
+
how that works.
|
|
324
|
+
"""
|
|
325
|
+
from fontTools.ttLib.tables.otTables import (
|
|
326
|
+
VarComponentFlags,
|
|
327
|
+
NO_VARIATION_INDEX,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
glyphSet = self.glyphSet
|
|
331
|
+
varc = glyphSet.varcTable
|
|
332
|
+
idx = varc.Coverage.glyphs.index(self.name)
|
|
333
|
+
glyph = varc.VarCompositeGlyphs.VarCompositeGlyph[idx]
|
|
334
|
+
|
|
335
|
+
from fontTools.varLib.multiVarStore import MultiVarStoreInstancer
|
|
336
|
+
from fontTools.varLib.varStore import VarStoreInstancer
|
|
337
|
+
|
|
338
|
+
fvarAxes = glyphSet.font["fvar"].axes
|
|
339
|
+
instancer = MultiVarStoreInstancer(
|
|
340
|
+
varc.MultiVarStore, fvarAxes, self.glyphSet.location
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
for comp in glyph.components:
|
|
344
|
+
if comp.flags & VarComponentFlags.HAVE_CONDITION:
|
|
345
|
+
condition = varc.ConditionList.ConditionTable[comp.conditionIndex]
|
|
346
|
+
if not _evaluateCondition(
|
|
347
|
+
condition, fvarAxes, self.glyphSet.location, instancer
|
|
348
|
+
):
|
|
349
|
+
continue
|
|
350
|
+
|
|
351
|
+
location = {}
|
|
352
|
+
if comp.axisIndicesIndex is not None:
|
|
353
|
+
axisIndices = varc.AxisIndicesList.Item[comp.axisIndicesIndex]
|
|
354
|
+
axisValues = Vector(comp.axisValues)
|
|
355
|
+
if comp.axisValuesVarIndex != NO_VARIATION_INDEX:
|
|
356
|
+
axisValues += fi2fl(instancer[comp.axisValuesVarIndex], 14)
|
|
357
|
+
assert len(axisIndices) == len(axisValues), (
|
|
358
|
+
len(axisIndices),
|
|
359
|
+
len(axisValues),
|
|
360
|
+
)
|
|
361
|
+
location = {
|
|
362
|
+
fvarAxes[i].axisTag: v for i, v in zip(axisIndices, axisValues)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if comp.transformVarIndex != NO_VARIATION_INDEX:
|
|
366
|
+
deltas = instancer[comp.transformVarIndex]
|
|
367
|
+
comp = deepcopy(comp)
|
|
368
|
+
comp.applyTransformDeltas(deltas)
|
|
369
|
+
transform = comp.transform
|
|
370
|
+
|
|
371
|
+
reset = comp.flags & VarComponentFlags.RESET_UNSPECIFIED_AXES
|
|
372
|
+
with self.glyphSet.glyphSet.pushLocation(location, reset):
|
|
373
|
+
with self.glyphSet.pushLocation(location, reset):
|
|
374
|
+
shouldDecompose = self.name == comp.glyphName
|
|
375
|
+
|
|
376
|
+
if not shouldDecompose:
|
|
377
|
+
try:
|
|
378
|
+
pen.addVarComponent(
|
|
379
|
+
comp.glyphName, transform, self.glyphSet.rawLocation
|
|
380
|
+
)
|
|
381
|
+
except AttributeError:
|
|
382
|
+
shouldDecompose = True
|
|
383
|
+
|
|
384
|
+
if shouldDecompose:
|
|
385
|
+
t = transform.toTransform()
|
|
386
|
+
compGlyphSet = (
|
|
387
|
+
self.glyphSet
|
|
388
|
+
if comp.glyphName != self.name
|
|
389
|
+
else glyphSet.glyphSet
|
|
390
|
+
)
|
|
391
|
+
g = compGlyphSet[comp.glyphName]
|
|
392
|
+
if isPointPen:
|
|
393
|
+
tPen = TransformPointPen(pen, t)
|
|
394
|
+
g.drawPoints(tPen)
|
|
395
|
+
else:
|
|
396
|
+
tPen = TransformPen(pen, t)
|
|
397
|
+
g.draw(tPen)
|
|
398
|
+
|
|
399
|
+
def draw(self, pen):
|
|
400
|
+
self._draw(pen, False)
|
|
401
|
+
|
|
402
|
+
def drawPoints(self, pen):
|
|
403
|
+
self._draw(pen, True)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _setCoordinates(glyph, coord, glyfTable, *, recalcBounds=True):
|
|
407
|
+
# Handle phantom points for (left, right, top, bottom) positions.
|
|
408
|
+
assert len(coord) >= 4
|
|
409
|
+
leftSideX = coord[-4][0]
|
|
410
|
+
rightSideX = coord[-3][0]
|
|
411
|
+
topSideY = coord[-2][1]
|
|
412
|
+
bottomSideY = coord[-1][1]
|
|
413
|
+
|
|
414
|
+
for _ in range(4):
|
|
415
|
+
del coord[-1]
|
|
416
|
+
|
|
417
|
+
if glyph.isComposite():
|
|
418
|
+
assert len(coord) == len(glyph.components)
|
|
419
|
+
glyph.components = [copy(comp) for comp in glyph.components] # Shallow copy
|
|
420
|
+
for p, comp in zip(coord, glyph.components):
|
|
421
|
+
if hasattr(comp, "x"):
|
|
422
|
+
comp.x, comp.y = p
|
|
423
|
+
elif glyph.numberOfContours == 0:
|
|
424
|
+
assert len(coord) == 0
|
|
425
|
+
else:
|
|
426
|
+
assert len(coord) == len(glyph.coordinates)
|
|
427
|
+
glyph.coordinates = coord
|
|
428
|
+
|
|
429
|
+
if recalcBounds:
|
|
430
|
+
glyph.recalcBounds(glyfTable)
|
|
431
|
+
|
|
432
|
+
horizontalAdvanceWidth = otRound(rightSideX - leftSideX)
|
|
433
|
+
verticalAdvanceWidth = otRound(topSideY - bottomSideY)
|
|
434
|
+
leftSideBearing = otRound(glyph.xMin - leftSideX)
|
|
435
|
+
topSideBearing = otRound(topSideY - glyph.yMax)
|
|
436
|
+
return (
|
|
437
|
+
horizontalAdvanceWidth,
|
|
438
|
+
leftSideBearing,
|
|
439
|
+
verticalAdvanceWidth,
|
|
440
|
+
topSideBearing,
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
class LerpGlyphSet(Mapping):
|
|
445
|
+
"""A glyphset that interpolates between two other glyphsets.
|
|
446
|
+
|
|
447
|
+
Factor is typically between 0 and 1. 0 means the first glyphset,
|
|
448
|
+
1 means the second glyphset, and 0.5 means the average of the
|
|
449
|
+
two glyphsets. Other values are possible, and can be useful to
|
|
450
|
+
extrapolate. Defaults to 0.5.
|
|
451
|
+
"""
|
|
452
|
+
|
|
453
|
+
def __init__(self, glyphset1, glyphset2, factor=0.5):
|
|
454
|
+
self.glyphset1 = glyphset1
|
|
455
|
+
self.glyphset2 = glyphset2
|
|
456
|
+
self.factor = factor
|
|
457
|
+
|
|
458
|
+
def __getitem__(self, glyphname):
|
|
459
|
+
if glyphname in self.glyphset1 and glyphname in self.glyphset2:
|
|
460
|
+
return LerpGlyph(glyphname, self)
|
|
461
|
+
raise KeyError(glyphname)
|
|
462
|
+
|
|
463
|
+
def __contains__(self, glyphname):
|
|
464
|
+
return glyphname in self.glyphset1 and glyphname in self.glyphset2
|
|
465
|
+
|
|
466
|
+
def __iter__(self):
|
|
467
|
+
set1 = set(self.glyphset1)
|
|
468
|
+
set2 = set(self.glyphset2)
|
|
469
|
+
return iter(set1.intersection(set2))
|
|
470
|
+
|
|
471
|
+
def __len__(self):
|
|
472
|
+
set1 = set(self.glyphset1)
|
|
473
|
+
set2 = set(self.glyphset2)
|
|
474
|
+
return len(set1.intersection(set2))
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class LerpGlyph:
|
|
478
|
+
def __init__(self, glyphname, glyphset):
|
|
479
|
+
self.glyphset = glyphset
|
|
480
|
+
self.glyphname = glyphname
|
|
481
|
+
|
|
482
|
+
def draw(self, pen):
|
|
483
|
+
recording1 = DecomposingRecordingPen(self.glyphset.glyphset1)
|
|
484
|
+
self.glyphset.glyphset1[self.glyphname].draw(recording1)
|
|
485
|
+
recording2 = DecomposingRecordingPen(self.glyphset.glyphset2)
|
|
486
|
+
self.glyphset.glyphset2[self.glyphname].draw(recording2)
|
|
487
|
+
|
|
488
|
+
factor = self.glyphset.factor
|
|
489
|
+
|
|
490
|
+
replayRecording(lerpRecordings(recording1.value, recording2.value, factor), pen)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Specialization of fontTools.misc.visitor to work with TTFont."""
|
|
2
|
+
|
|
3
|
+
from fontTools.misc.visitor import Visitor
|
|
4
|
+
from fontTools.ttLib import TTFont
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TTVisitor(Visitor):
|
|
8
|
+
def visitAttr(self, obj, attr, value, *args, **kwargs):
|
|
9
|
+
if isinstance(value, TTFont):
|
|
10
|
+
return False
|
|
11
|
+
super().visitAttr(obj, attr, value, *args, **kwargs)
|
|
12
|
+
|
|
13
|
+
def visit(self, obj, *args, **kwargs):
|
|
14
|
+
if hasattr(obj, "ensureDecompiled"):
|
|
15
|
+
obj.ensureDecompiled(recurse=False)
|
|
16
|
+
super().visit(obj, *args, **kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@TTVisitor.register(TTFont)
|
|
20
|
+
def visit(visitor, font, *args, **kwargs):
|
|
21
|
+
# Some objects have links back to TTFont; even though we
|
|
22
|
+
# have a check in visitAttr to stop them from recursing
|
|
23
|
+
# onto TTFont, sometimes they still do, for example when
|
|
24
|
+
# someone overrides visitAttr.
|
|
25
|
+
if hasattr(visitor, "font"):
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
visitor.font = font
|
|
29
|
+
for tag in font.keys():
|
|
30
|
+
visitor.visit(font[tag], *args, **kwargs)
|
|
31
|
+
del visitor.font
|
|
32
|
+
return False
|