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
|
Binary file
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
from fontTools.feaLib.error import FeatureLibError, IncludedFeaNotFound
|
|
2
|
+
from fontTools.feaLib.location import FeatureLibLocation
|
|
3
|
+
import re
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import cython
|
|
8
|
+
except ImportError:
|
|
9
|
+
# if cython not installed, use mock module with no-op decorators and types
|
|
10
|
+
from fontTools.misc import cython
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Lexer(object):
|
|
14
|
+
NUMBER = "NUMBER"
|
|
15
|
+
HEXADECIMAL = "HEXADECIMAL"
|
|
16
|
+
OCTAL = "OCTAL"
|
|
17
|
+
NUMBERS = (NUMBER, HEXADECIMAL, OCTAL)
|
|
18
|
+
FLOAT = "FLOAT"
|
|
19
|
+
STRING = "STRING"
|
|
20
|
+
NAME = "NAME"
|
|
21
|
+
FILENAME = "FILENAME"
|
|
22
|
+
GLYPHCLASS = "GLYPHCLASS"
|
|
23
|
+
CID = "CID"
|
|
24
|
+
SYMBOL = "SYMBOL"
|
|
25
|
+
COMMENT = "COMMENT"
|
|
26
|
+
NEWLINE = "NEWLINE"
|
|
27
|
+
ANONYMOUS_BLOCK = "ANONYMOUS_BLOCK"
|
|
28
|
+
|
|
29
|
+
CHAR_WHITESPACE_ = " \t"
|
|
30
|
+
CHAR_NEWLINE_ = "\r\n"
|
|
31
|
+
CHAR_SYMBOL_ = ",;:-+'{}[]<>()="
|
|
32
|
+
CHAR_DIGIT_ = "0123456789"
|
|
33
|
+
CHAR_HEXDIGIT_ = "0123456789ABCDEFabcdef"
|
|
34
|
+
CHAR_LETTER_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
35
|
+
CHAR_NAME_START_ = CHAR_LETTER_ + "_+*:.^~!\\"
|
|
36
|
+
CHAR_NAME_CONTINUATION_ = CHAR_LETTER_ + CHAR_DIGIT_ + "_.+*:^~!/-"
|
|
37
|
+
|
|
38
|
+
RE_GLYPHCLASS = re.compile(r"^[A-Za-z_0-9.\-]+$")
|
|
39
|
+
|
|
40
|
+
MODE_NORMAL_ = "NORMAL"
|
|
41
|
+
MODE_FILENAME_ = "FILENAME"
|
|
42
|
+
|
|
43
|
+
def __init__(self, text, filename):
|
|
44
|
+
self.filename_ = filename
|
|
45
|
+
self.line_ = 1
|
|
46
|
+
self.pos_ = 0
|
|
47
|
+
self.line_start_ = 0
|
|
48
|
+
self.text_ = text
|
|
49
|
+
self.text_length_ = len(text)
|
|
50
|
+
self.mode_ = Lexer.MODE_NORMAL_
|
|
51
|
+
|
|
52
|
+
def __iter__(self):
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def next(self): # Python 2
|
|
56
|
+
return self.__next__()
|
|
57
|
+
|
|
58
|
+
def __next__(self): # Python 3
|
|
59
|
+
while True:
|
|
60
|
+
token_type, token, location = self.next_()
|
|
61
|
+
if token_type != Lexer.NEWLINE:
|
|
62
|
+
return (token_type, token, location)
|
|
63
|
+
|
|
64
|
+
def location_(self):
|
|
65
|
+
column = self.pos_ - self.line_start_ + 1
|
|
66
|
+
return FeatureLibLocation(self.filename_ or "<features>", self.line_, column)
|
|
67
|
+
|
|
68
|
+
def next_(self):
|
|
69
|
+
self.scan_over_(Lexer.CHAR_WHITESPACE_)
|
|
70
|
+
location = self.location_()
|
|
71
|
+
start = self.pos_
|
|
72
|
+
text = self.text_
|
|
73
|
+
limit = len(text)
|
|
74
|
+
if start >= limit:
|
|
75
|
+
raise StopIteration()
|
|
76
|
+
cur_char = text[start]
|
|
77
|
+
next_char = text[start + 1] if start + 1 < limit else None
|
|
78
|
+
|
|
79
|
+
if cur_char == "\n":
|
|
80
|
+
self.pos_ += 1
|
|
81
|
+
self.line_ += 1
|
|
82
|
+
self.line_start_ = self.pos_
|
|
83
|
+
return (Lexer.NEWLINE, None, location)
|
|
84
|
+
if cur_char == "\r":
|
|
85
|
+
self.pos_ += 2 if next_char == "\n" else 1
|
|
86
|
+
self.line_ += 1
|
|
87
|
+
self.line_start_ = self.pos_
|
|
88
|
+
return (Lexer.NEWLINE, None, location)
|
|
89
|
+
if cur_char == "#":
|
|
90
|
+
self.scan_until_(Lexer.CHAR_NEWLINE_)
|
|
91
|
+
return (Lexer.COMMENT, text[start : self.pos_], location)
|
|
92
|
+
|
|
93
|
+
if self.mode_ is Lexer.MODE_FILENAME_:
|
|
94
|
+
if cur_char != "(":
|
|
95
|
+
raise FeatureLibError("Expected '(' before file name", location)
|
|
96
|
+
self.scan_until_(")")
|
|
97
|
+
cur_char = text[self.pos_] if self.pos_ < limit else None
|
|
98
|
+
if cur_char != ")":
|
|
99
|
+
raise FeatureLibError("Expected ')' after file name", location)
|
|
100
|
+
self.pos_ += 1
|
|
101
|
+
self.mode_ = Lexer.MODE_NORMAL_
|
|
102
|
+
return (Lexer.FILENAME, text[start + 1 : self.pos_ - 1], location)
|
|
103
|
+
|
|
104
|
+
if cur_char == "\\" and next_char in Lexer.CHAR_DIGIT_:
|
|
105
|
+
self.pos_ += 1
|
|
106
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
107
|
+
return (Lexer.CID, int(text[start + 1 : self.pos_], 10), location)
|
|
108
|
+
if cur_char == "@":
|
|
109
|
+
self.pos_ += 1
|
|
110
|
+
self.scan_over_(Lexer.CHAR_NAME_CONTINUATION_)
|
|
111
|
+
glyphclass = text[start + 1 : self.pos_]
|
|
112
|
+
if len(glyphclass) < 1:
|
|
113
|
+
raise FeatureLibError("Expected glyph class name", location)
|
|
114
|
+
if not Lexer.RE_GLYPHCLASS.match(glyphclass):
|
|
115
|
+
raise FeatureLibError(
|
|
116
|
+
"Glyph class names must consist of letters, digits, "
|
|
117
|
+
"underscore, period or hyphen",
|
|
118
|
+
location,
|
|
119
|
+
)
|
|
120
|
+
return (Lexer.GLYPHCLASS, glyphclass, location)
|
|
121
|
+
if cur_char in Lexer.CHAR_NAME_START_:
|
|
122
|
+
self.pos_ += 1
|
|
123
|
+
self.scan_over_(Lexer.CHAR_NAME_CONTINUATION_)
|
|
124
|
+
token = text[start : self.pos_]
|
|
125
|
+
if token == "include":
|
|
126
|
+
self.mode_ = Lexer.MODE_FILENAME_
|
|
127
|
+
return (Lexer.NAME, token, location)
|
|
128
|
+
if cur_char == "0" and next_char in "xX":
|
|
129
|
+
self.pos_ += 2
|
|
130
|
+
self.scan_over_(Lexer.CHAR_HEXDIGIT_)
|
|
131
|
+
return (Lexer.HEXADECIMAL, int(text[start : self.pos_], 16), location)
|
|
132
|
+
if cur_char == "0" and next_char in Lexer.CHAR_DIGIT_:
|
|
133
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
134
|
+
return (Lexer.OCTAL, int(text[start : self.pos_], 8), location)
|
|
135
|
+
if cur_char in Lexer.CHAR_DIGIT_:
|
|
136
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
137
|
+
if self.pos_ >= limit or text[self.pos_] != ".":
|
|
138
|
+
return (Lexer.NUMBER, int(text[start : self.pos_], 10), location)
|
|
139
|
+
self.scan_over_(".")
|
|
140
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
141
|
+
return (Lexer.FLOAT, float(text[start : self.pos_]), location)
|
|
142
|
+
if cur_char == "-" and next_char in Lexer.CHAR_DIGIT_:
|
|
143
|
+
self.pos_ += 1
|
|
144
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
145
|
+
if self.pos_ >= limit or text[self.pos_] != ".":
|
|
146
|
+
return (Lexer.NUMBER, int(text[start : self.pos_], 10), location)
|
|
147
|
+
self.scan_over_(".")
|
|
148
|
+
self.scan_over_(Lexer.CHAR_DIGIT_)
|
|
149
|
+
return (Lexer.FLOAT, float(text[start : self.pos_]), location)
|
|
150
|
+
if cur_char in Lexer.CHAR_SYMBOL_:
|
|
151
|
+
self.pos_ += 1
|
|
152
|
+
return (Lexer.SYMBOL, cur_char, location)
|
|
153
|
+
if cur_char == '"':
|
|
154
|
+
self.pos_ += 1
|
|
155
|
+
self.scan_until_('"')
|
|
156
|
+
if self.pos_ < self.text_length_ and self.text_[self.pos_] == '"':
|
|
157
|
+
self.pos_ += 1
|
|
158
|
+
# strip newlines embedded within a string
|
|
159
|
+
string = re.sub("[\r\n]", "", text[start + 1 : self.pos_ - 1])
|
|
160
|
+
return (Lexer.STRING, string, location)
|
|
161
|
+
else:
|
|
162
|
+
raise FeatureLibError("Expected '\"' to terminate string", location)
|
|
163
|
+
raise FeatureLibError("Unexpected character: %r" % cur_char, location)
|
|
164
|
+
|
|
165
|
+
def scan_over_(self, valid):
|
|
166
|
+
p = self.pos_
|
|
167
|
+
while p < self.text_length_ and self.text_[p] in valid:
|
|
168
|
+
p += 1
|
|
169
|
+
self.pos_ = p
|
|
170
|
+
|
|
171
|
+
def scan_until_(self, stop_at):
|
|
172
|
+
p = self.pos_
|
|
173
|
+
while p < self.text_length_ and self.text_[p] not in stop_at:
|
|
174
|
+
p += 1
|
|
175
|
+
self.pos_ = p
|
|
176
|
+
|
|
177
|
+
def scan_anonymous_block(self, tag):
|
|
178
|
+
location = self.location_()
|
|
179
|
+
tag = tag.strip()
|
|
180
|
+
self.scan_until_(Lexer.CHAR_NEWLINE_)
|
|
181
|
+
self.scan_over_(Lexer.CHAR_NEWLINE_)
|
|
182
|
+
regexp = r"}\s*" + tag + r"\s*;"
|
|
183
|
+
split = re.split(regexp, self.text_[self.pos_ :], maxsplit=1)
|
|
184
|
+
if len(split) != 2:
|
|
185
|
+
raise FeatureLibError(
|
|
186
|
+
"Expected '} %s;' to terminate anonymous block" % tag, location
|
|
187
|
+
)
|
|
188
|
+
self.pos_ += len(split[0])
|
|
189
|
+
return (Lexer.ANONYMOUS_BLOCK, split[0], location)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class IncludingLexer(object):
|
|
193
|
+
"""A Lexer that follows include statements.
|
|
194
|
+
|
|
195
|
+
The OpenType feature file specification states that due to
|
|
196
|
+
historical reasons, relative imports should be resolved in this
|
|
197
|
+
order:
|
|
198
|
+
|
|
199
|
+
1. If the source font is UFO format, then relative to the UFO's
|
|
200
|
+
font directory
|
|
201
|
+
2. relative to the top-level include file
|
|
202
|
+
3. relative to the parent include file
|
|
203
|
+
|
|
204
|
+
We only support 1 (via includeDir) and 2.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def __init__(self, featurefile, *, includeDir=None):
|
|
208
|
+
"""Initializes an IncludingLexer.
|
|
209
|
+
|
|
210
|
+
Behavior:
|
|
211
|
+
If includeDir is passed, it will be used to determine the top-level
|
|
212
|
+
include directory to use for all encountered include statements. If it is
|
|
213
|
+
not passed, ``os.path.dirname(featurefile)`` will be considered the
|
|
214
|
+
include directory.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
self.lexers_ = [self.make_lexer_(featurefile)]
|
|
218
|
+
self.featurefilepath = self.lexers_[0].filename_
|
|
219
|
+
self.includeDir = includeDir
|
|
220
|
+
|
|
221
|
+
def __iter__(self):
|
|
222
|
+
return self
|
|
223
|
+
|
|
224
|
+
def next(self): # Python 2
|
|
225
|
+
return self.__next__()
|
|
226
|
+
|
|
227
|
+
def __next__(self): # Python 3
|
|
228
|
+
while self.lexers_:
|
|
229
|
+
lexer = self.lexers_[-1]
|
|
230
|
+
try:
|
|
231
|
+
token_type, token, location = next(lexer)
|
|
232
|
+
except StopIteration:
|
|
233
|
+
self.lexers_.pop()
|
|
234
|
+
continue
|
|
235
|
+
if token_type is Lexer.NAME and token == "include":
|
|
236
|
+
fname_type, fname_token, fname_location = lexer.next()
|
|
237
|
+
if fname_type is not Lexer.FILENAME:
|
|
238
|
+
raise FeatureLibError("Expected file name", fname_location)
|
|
239
|
+
# semi_type, semi_token, semi_location = lexer.next()
|
|
240
|
+
# if semi_type is not Lexer.SYMBOL or semi_token != ";":
|
|
241
|
+
# raise FeatureLibError("Expected ';'", semi_location)
|
|
242
|
+
if os.path.isabs(fname_token):
|
|
243
|
+
path = fname_token
|
|
244
|
+
else:
|
|
245
|
+
if self.includeDir is not None:
|
|
246
|
+
curpath = self.includeDir
|
|
247
|
+
elif self.featurefilepath is not None:
|
|
248
|
+
curpath = os.path.dirname(self.featurefilepath)
|
|
249
|
+
else:
|
|
250
|
+
# if the IncludingLexer was initialized from an in-memory
|
|
251
|
+
# file-like stream, it doesn't have a 'name' pointing to
|
|
252
|
+
# its filesystem path, therefore we fall back to using the
|
|
253
|
+
# current working directory to resolve relative includes
|
|
254
|
+
curpath = os.getcwd()
|
|
255
|
+
path = os.path.join(curpath, fname_token)
|
|
256
|
+
if len(self.lexers_) >= 5:
|
|
257
|
+
raise FeatureLibError("Too many recursive includes", fname_location)
|
|
258
|
+
try:
|
|
259
|
+
self.lexers_.append(self.make_lexer_(path))
|
|
260
|
+
except FileNotFoundError as err:
|
|
261
|
+
raise IncludedFeaNotFound(fname_token, fname_location) from err
|
|
262
|
+
else:
|
|
263
|
+
return (token_type, token, location)
|
|
264
|
+
raise StopIteration()
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def make_lexer_(file_or_path):
|
|
268
|
+
if hasattr(file_or_path, "read"):
|
|
269
|
+
fileobj, closing = file_or_path, False
|
|
270
|
+
else:
|
|
271
|
+
filename, closing = file_or_path, True
|
|
272
|
+
fileobj = open(filename, "r", encoding="utf-8-sig")
|
|
273
|
+
data = fileobj.read()
|
|
274
|
+
filename = getattr(fileobj, "name", None)
|
|
275
|
+
if closing:
|
|
276
|
+
fileobj.close()
|
|
277
|
+
return Lexer(data, filename)
|
|
278
|
+
|
|
279
|
+
def scan_anonymous_block(self, tag):
|
|
280
|
+
return self.lexers_[-1].scan_anonymous_block(tag)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class NonIncludingLexer(IncludingLexer):
|
|
284
|
+
"""Lexer that does not follow `include` statements, emits them as-is."""
|
|
285
|
+
|
|
286
|
+
def __next__(self): # Python 3
|
|
287
|
+
return next(self.lexers_[0])
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import NamedTuple
|
|
2
|
+
|
|
3
|
+
LOOKUP_DEBUG_INFO_KEY = "com.github.fonttools.feaLib"
|
|
4
|
+
LOOKUP_DEBUG_ENV_VAR = "FONTTOOLS_LOOKUP_DEBUGGING"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LookupDebugInfo(NamedTuple):
|
|
8
|
+
"""Information about where a lookup came from, to be embedded in a font"""
|
|
9
|
+
|
|
10
|
+
location: str
|
|
11
|
+
name: str
|
|
12
|
+
feature: list
|