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,332 @@
|
|
|
1
|
+
from fontTools.misc import sstruct
|
|
2
|
+
from fontTools.misc.fixedTools import (
|
|
3
|
+
fixedToFloat as fi2fl,
|
|
4
|
+
floatToFixed as fl2fi,
|
|
5
|
+
floatToFixedToStr as fl2str,
|
|
6
|
+
strToFixedToFloat as str2fl,
|
|
7
|
+
)
|
|
8
|
+
from fontTools.misc.textTools import bytesjoin, safeEval
|
|
9
|
+
from fontTools.ttLib import TTLibError
|
|
10
|
+
from . import DefaultTable
|
|
11
|
+
import struct
|
|
12
|
+
from collections.abc import MutableMapping
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Apple's documentation of 'trak':
|
|
16
|
+
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
|
|
17
|
+
|
|
18
|
+
TRAK_HEADER_FORMAT = """
|
|
19
|
+
> # big endian
|
|
20
|
+
version: 16.16F
|
|
21
|
+
format: H
|
|
22
|
+
horizOffset: H
|
|
23
|
+
vertOffset: H
|
|
24
|
+
reserved: H
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
TRAK_HEADER_FORMAT_SIZE = sstruct.calcsize(TRAK_HEADER_FORMAT)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
TRACK_DATA_FORMAT = """
|
|
31
|
+
> # big endian
|
|
32
|
+
nTracks: H
|
|
33
|
+
nSizes: H
|
|
34
|
+
sizeTableOffset: L
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
TRACK_DATA_FORMAT_SIZE = sstruct.calcsize(TRACK_DATA_FORMAT)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
TRACK_TABLE_ENTRY_FORMAT = """
|
|
41
|
+
> # big endian
|
|
42
|
+
track: 16.16F
|
|
43
|
+
nameIndex: H
|
|
44
|
+
offset: H
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
TRACK_TABLE_ENTRY_FORMAT_SIZE = sstruct.calcsize(TRACK_TABLE_ENTRY_FORMAT)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# size values are actually '16.16F' fixed-point values, but here I do the
|
|
51
|
+
# fixedToFloat conversion manually instead of relying on sstruct
|
|
52
|
+
SIZE_VALUE_FORMAT = ">l"
|
|
53
|
+
SIZE_VALUE_FORMAT_SIZE = struct.calcsize(SIZE_VALUE_FORMAT)
|
|
54
|
+
|
|
55
|
+
# per-Size values are in 'FUnits', i.e. 16-bit signed integers
|
|
56
|
+
PER_SIZE_VALUE_FORMAT = ">h"
|
|
57
|
+
PER_SIZE_VALUE_FORMAT_SIZE = struct.calcsize(PER_SIZE_VALUE_FORMAT)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class table__t_r_a_k(DefaultTable.DefaultTable):
|
|
61
|
+
"""The AAT ``trak`` table can store per-size adjustments to each glyph's
|
|
62
|
+
sidebearings to make when tracking is enabled, which applications can
|
|
63
|
+
use to provide more visually balanced line spacing.
|
|
64
|
+
|
|
65
|
+
See also https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
dependencies = ["name"]
|
|
69
|
+
|
|
70
|
+
def compile(self, ttFont):
|
|
71
|
+
dataList = []
|
|
72
|
+
offset = TRAK_HEADER_FORMAT_SIZE
|
|
73
|
+
for direction in ("horiz", "vert"):
|
|
74
|
+
trackData = getattr(self, direction + "Data", TrackData())
|
|
75
|
+
offsetName = direction + "Offset"
|
|
76
|
+
# set offset to 0 if None or empty
|
|
77
|
+
if not trackData:
|
|
78
|
+
setattr(self, offsetName, 0)
|
|
79
|
+
continue
|
|
80
|
+
# TrackData table format must be longword aligned
|
|
81
|
+
alignedOffset = (offset + 3) & ~3
|
|
82
|
+
padding, offset = b"\x00" * (alignedOffset - offset), alignedOffset
|
|
83
|
+
setattr(self, offsetName, offset)
|
|
84
|
+
|
|
85
|
+
data = trackData.compile(offset)
|
|
86
|
+
offset += len(data)
|
|
87
|
+
dataList.append(padding + data)
|
|
88
|
+
|
|
89
|
+
self.reserved = 0
|
|
90
|
+
tableData = bytesjoin([sstruct.pack(TRAK_HEADER_FORMAT, self)] + dataList)
|
|
91
|
+
return tableData
|
|
92
|
+
|
|
93
|
+
def decompile(self, data, ttFont):
|
|
94
|
+
sstruct.unpack(TRAK_HEADER_FORMAT, data[:TRAK_HEADER_FORMAT_SIZE], self)
|
|
95
|
+
for direction in ("horiz", "vert"):
|
|
96
|
+
trackData = TrackData()
|
|
97
|
+
offset = getattr(self, direction + "Offset")
|
|
98
|
+
if offset != 0:
|
|
99
|
+
trackData.decompile(data, offset)
|
|
100
|
+
setattr(self, direction + "Data", trackData)
|
|
101
|
+
|
|
102
|
+
def toXML(self, writer, ttFont):
|
|
103
|
+
writer.simpletag("version", value=self.version)
|
|
104
|
+
writer.newline()
|
|
105
|
+
writer.simpletag("format", value=self.format)
|
|
106
|
+
writer.newline()
|
|
107
|
+
for direction in ("horiz", "vert"):
|
|
108
|
+
dataName = direction + "Data"
|
|
109
|
+
writer.begintag(dataName)
|
|
110
|
+
writer.newline()
|
|
111
|
+
trackData = getattr(self, dataName, TrackData())
|
|
112
|
+
trackData.toXML(writer, ttFont)
|
|
113
|
+
writer.endtag(dataName)
|
|
114
|
+
writer.newline()
|
|
115
|
+
|
|
116
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
117
|
+
if name == "version":
|
|
118
|
+
self.version = safeEval(attrs["value"])
|
|
119
|
+
elif name == "format":
|
|
120
|
+
self.format = safeEval(attrs["value"])
|
|
121
|
+
elif name in ("horizData", "vertData"):
|
|
122
|
+
trackData = TrackData()
|
|
123
|
+
setattr(self, name, trackData)
|
|
124
|
+
for element in content:
|
|
125
|
+
if not isinstance(element, tuple):
|
|
126
|
+
continue
|
|
127
|
+
name, attrs, content_ = element
|
|
128
|
+
trackData.fromXML(name, attrs, content_, ttFont)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class TrackData(MutableMapping):
|
|
132
|
+
def __init__(self, initialdata={}):
|
|
133
|
+
self._map = dict(initialdata)
|
|
134
|
+
|
|
135
|
+
def compile(self, offset):
|
|
136
|
+
nTracks = len(self)
|
|
137
|
+
sizes = self.sizes()
|
|
138
|
+
nSizes = len(sizes)
|
|
139
|
+
|
|
140
|
+
# offset to the start of the size subtable
|
|
141
|
+
offset += TRACK_DATA_FORMAT_SIZE + TRACK_TABLE_ENTRY_FORMAT_SIZE * nTracks
|
|
142
|
+
trackDataHeader = sstruct.pack(
|
|
143
|
+
TRACK_DATA_FORMAT,
|
|
144
|
+
{"nTracks": nTracks, "nSizes": nSizes, "sizeTableOffset": offset},
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
entryDataList = []
|
|
148
|
+
perSizeDataList = []
|
|
149
|
+
# offset to per-size tracking values
|
|
150
|
+
offset += SIZE_VALUE_FORMAT_SIZE * nSizes
|
|
151
|
+
# sort track table entries by track value
|
|
152
|
+
for track, entry in sorted(self.items()):
|
|
153
|
+
assert entry.nameIndex is not None
|
|
154
|
+
entry.track = track
|
|
155
|
+
entry.offset = offset
|
|
156
|
+
entryDataList += [sstruct.pack(TRACK_TABLE_ENTRY_FORMAT, entry)]
|
|
157
|
+
# sort per-size values by size
|
|
158
|
+
for size, value in sorted(entry.items()):
|
|
159
|
+
perSizeDataList += [struct.pack(PER_SIZE_VALUE_FORMAT, value)]
|
|
160
|
+
offset += PER_SIZE_VALUE_FORMAT_SIZE * nSizes
|
|
161
|
+
# sort size values
|
|
162
|
+
sizeDataList = [
|
|
163
|
+
struct.pack(SIZE_VALUE_FORMAT, fl2fi(sv, 16)) for sv in sorted(sizes)
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
data = bytesjoin(
|
|
167
|
+
[trackDataHeader] + entryDataList + sizeDataList + perSizeDataList
|
|
168
|
+
)
|
|
169
|
+
return data
|
|
170
|
+
|
|
171
|
+
def decompile(self, data, offset):
|
|
172
|
+
# initial offset is from the start of trak table to the current TrackData
|
|
173
|
+
trackDataHeader = data[offset : offset + TRACK_DATA_FORMAT_SIZE]
|
|
174
|
+
if len(trackDataHeader) != TRACK_DATA_FORMAT_SIZE:
|
|
175
|
+
raise TTLibError("not enough data to decompile TrackData header")
|
|
176
|
+
sstruct.unpack(TRACK_DATA_FORMAT, trackDataHeader, self)
|
|
177
|
+
offset += TRACK_DATA_FORMAT_SIZE
|
|
178
|
+
|
|
179
|
+
nSizes = self.nSizes
|
|
180
|
+
sizeTableOffset = self.sizeTableOffset
|
|
181
|
+
sizeTable = []
|
|
182
|
+
for i in range(nSizes):
|
|
183
|
+
sizeValueData = data[
|
|
184
|
+
sizeTableOffset : sizeTableOffset + SIZE_VALUE_FORMAT_SIZE
|
|
185
|
+
]
|
|
186
|
+
if len(sizeValueData) < SIZE_VALUE_FORMAT_SIZE:
|
|
187
|
+
raise TTLibError("not enough data to decompile TrackData size subtable")
|
|
188
|
+
(sizeValue,) = struct.unpack(SIZE_VALUE_FORMAT, sizeValueData)
|
|
189
|
+
sizeTable.append(fi2fl(sizeValue, 16))
|
|
190
|
+
sizeTableOffset += SIZE_VALUE_FORMAT_SIZE
|
|
191
|
+
|
|
192
|
+
for i in range(self.nTracks):
|
|
193
|
+
entry = TrackTableEntry()
|
|
194
|
+
entryData = data[offset : offset + TRACK_TABLE_ENTRY_FORMAT_SIZE]
|
|
195
|
+
if len(entryData) < TRACK_TABLE_ENTRY_FORMAT_SIZE:
|
|
196
|
+
raise TTLibError("not enough data to decompile TrackTableEntry record")
|
|
197
|
+
sstruct.unpack(TRACK_TABLE_ENTRY_FORMAT, entryData, entry)
|
|
198
|
+
perSizeOffset = entry.offset
|
|
199
|
+
for j in range(nSizes):
|
|
200
|
+
size = sizeTable[j]
|
|
201
|
+
perSizeValueData = data[
|
|
202
|
+
perSizeOffset : perSizeOffset + PER_SIZE_VALUE_FORMAT_SIZE
|
|
203
|
+
]
|
|
204
|
+
if len(perSizeValueData) < PER_SIZE_VALUE_FORMAT_SIZE:
|
|
205
|
+
raise TTLibError(
|
|
206
|
+
"not enough data to decompile per-size track values"
|
|
207
|
+
)
|
|
208
|
+
(perSizeValue,) = struct.unpack(PER_SIZE_VALUE_FORMAT, perSizeValueData)
|
|
209
|
+
entry[size] = perSizeValue
|
|
210
|
+
perSizeOffset += PER_SIZE_VALUE_FORMAT_SIZE
|
|
211
|
+
self[entry.track] = entry
|
|
212
|
+
offset += TRACK_TABLE_ENTRY_FORMAT_SIZE
|
|
213
|
+
|
|
214
|
+
def toXML(self, writer, ttFont):
|
|
215
|
+
nTracks = len(self)
|
|
216
|
+
nSizes = len(self.sizes())
|
|
217
|
+
writer.comment("nTracks=%d, nSizes=%d" % (nTracks, nSizes))
|
|
218
|
+
writer.newline()
|
|
219
|
+
for track, entry in sorted(self.items()):
|
|
220
|
+
assert entry.nameIndex is not None
|
|
221
|
+
entry.track = track
|
|
222
|
+
entry.toXML(writer, ttFont)
|
|
223
|
+
|
|
224
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
225
|
+
if name != "trackEntry":
|
|
226
|
+
return
|
|
227
|
+
entry = TrackTableEntry()
|
|
228
|
+
entry.fromXML(name, attrs, content, ttFont)
|
|
229
|
+
self[entry.track] = entry
|
|
230
|
+
|
|
231
|
+
def sizes(self):
|
|
232
|
+
if not self:
|
|
233
|
+
return frozenset()
|
|
234
|
+
tracks = list(self.tracks())
|
|
235
|
+
sizes = self[tracks.pop(0)].sizes()
|
|
236
|
+
for track in tracks:
|
|
237
|
+
entrySizes = self[track].sizes()
|
|
238
|
+
if sizes != entrySizes:
|
|
239
|
+
raise TTLibError(
|
|
240
|
+
"'trak' table entries must specify the same sizes: "
|
|
241
|
+
"%s != %s" % (sorted(sizes), sorted(entrySizes))
|
|
242
|
+
)
|
|
243
|
+
return frozenset(sizes)
|
|
244
|
+
|
|
245
|
+
def __getitem__(self, track):
|
|
246
|
+
return self._map[track]
|
|
247
|
+
|
|
248
|
+
def __delitem__(self, track):
|
|
249
|
+
del self._map[track]
|
|
250
|
+
|
|
251
|
+
def __setitem__(self, track, entry):
|
|
252
|
+
self._map[track] = entry
|
|
253
|
+
|
|
254
|
+
def __len__(self):
|
|
255
|
+
return len(self._map)
|
|
256
|
+
|
|
257
|
+
def __iter__(self):
|
|
258
|
+
return iter(self._map)
|
|
259
|
+
|
|
260
|
+
def keys(self):
|
|
261
|
+
return self._map.keys()
|
|
262
|
+
|
|
263
|
+
tracks = keys
|
|
264
|
+
|
|
265
|
+
def __repr__(self):
|
|
266
|
+
return "TrackData({})".format(self._map if self else "")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class TrackTableEntry(MutableMapping):
|
|
270
|
+
def __init__(self, values={}, nameIndex=None):
|
|
271
|
+
self.nameIndex = nameIndex
|
|
272
|
+
self._map = dict(values)
|
|
273
|
+
|
|
274
|
+
def toXML(self, writer, ttFont):
|
|
275
|
+
name = ttFont["name"].getDebugName(self.nameIndex)
|
|
276
|
+
writer.begintag(
|
|
277
|
+
"trackEntry",
|
|
278
|
+
(("value", fl2str(self.track, 16)), ("nameIndex", self.nameIndex)),
|
|
279
|
+
)
|
|
280
|
+
writer.newline()
|
|
281
|
+
if name:
|
|
282
|
+
writer.comment(name)
|
|
283
|
+
writer.newline()
|
|
284
|
+
for size, perSizeValue in sorted(self.items()):
|
|
285
|
+
writer.simpletag("track", size=fl2str(size, 16), value=perSizeValue)
|
|
286
|
+
writer.newline()
|
|
287
|
+
writer.endtag("trackEntry")
|
|
288
|
+
writer.newline()
|
|
289
|
+
|
|
290
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
291
|
+
self.track = str2fl(attrs["value"], 16)
|
|
292
|
+
self.nameIndex = safeEval(attrs["nameIndex"])
|
|
293
|
+
for element in content:
|
|
294
|
+
if not isinstance(element, tuple):
|
|
295
|
+
continue
|
|
296
|
+
name, attrs, _ = element
|
|
297
|
+
if name != "track":
|
|
298
|
+
continue
|
|
299
|
+
size = str2fl(attrs["size"], 16)
|
|
300
|
+
self[size] = safeEval(attrs["value"])
|
|
301
|
+
|
|
302
|
+
def __getitem__(self, size):
|
|
303
|
+
return self._map[size]
|
|
304
|
+
|
|
305
|
+
def __delitem__(self, size):
|
|
306
|
+
del self._map[size]
|
|
307
|
+
|
|
308
|
+
def __setitem__(self, size, value):
|
|
309
|
+
self._map[size] = value
|
|
310
|
+
|
|
311
|
+
def __len__(self):
|
|
312
|
+
return len(self._map)
|
|
313
|
+
|
|
314
|
+
def __iter__(self):
|
|
315
|
+
return iter(self._map)
|
|
316
|
+
|
|
317
|
+
def keys(self):
|
|
318
|
+
return self._map.keys()
|
|
319
|
+
|
|
320
|
+
sizes = keys
|
|
321
|
+
|
|
322
|
+
def __repr__(self):
|
|
323
|
+
return "TrackTableEntry({}, nameIndex={})".format(self._map, self.nameIndex)
|
|
324
|
+
|
|
325
|
+
def __eq__(self, other):
|
|
326
|
+
if not isinstance(other, self.__class__):
|
|
327
|
+
return NotImplemented
|
|
328
|
+
return self.nameIndex == other.nameIndex and dict(self) == dict(other)
|
|
329
|
+
|
|
330
|
+
def __ne__(self, other):
|
|
331
|
+
result = self.__eq__(other)
|
|
332
|
+
return result if result is NotImplemented else not result
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from fontTools.misc import sstruct
|
|
2
|
+
from fontTools.misc.textTools import safeEval
|
|
3
|
+
from fontTools.misc.fixedTools import (
|
|
4
|
+
ensureVersionIsLong as fi2ve,
|
|
5
|
+
versionToFixed as ve2fi,
|
|
6
|
+
)
|
|
7
|
+
from . import DefaultTable
|
|
8
|
+
import math
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
vheaFormat = """
|
|
12
|
+
> # big endian
|
|
13
|
+
tableVersion: L
|
|
14
|
+
ascent: h
|
|
15
|
+
descent: h
|
|
16
|
+
lineGap: h
|
|
17
|
+
advanceHeightMax: H
|
|
18
|
+
minTopSideBearing: h
|
|
19
|
+
minBottomSideBearing: h
|
|
20
|
+
yMaxExtent: h
|
|
21
|
+
caretSlopeRise: h
|
|
22
|
+
caretSlopeRun: h
|
|
23
|
+
caretOffset: h
|
|
24
|
+
reserved1: h
|
|
25
|
+
reserved2: h
|
|
26
|
+
reserved3: h
|
|
27
|
+
reserved4: h
|
|
28
|
+
metricDataFormat: h
|
|
29
|
+
numberOfVMetrics: H
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class table__v_h_e_a(DefaultTable.DefaultTable):
|
|
34
|
+
"""Vertical Header table
|
|
35
|
+
|
|
36
|
+
The ``vhea`` table contains information needed during vertical
|
|
37
|
+
text layout.
|
|
38
|
+
|
|
39
|
+
.. note::
|
|
40
|
+
This converter class is kept in sync with the :class:`._h_h_e_a.table__h_h_e_a`
|
|
41
|
+
table constructor.
|
|
42
|
+
|
|
43
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/vhea
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Note: Keep in sync with table__h_h_e_a
|
|
47
|
+
|
|
48
|
+
dependencies = ["vmtx", "glyf", "CFF ", "CFF2"]
|
|
49
|
+
|
|
50
|
+
def decompile(self, data, ttFont):
|
|
51
|
+
sstruct.unpack(vheaFormat, data, self)
|
|
52
|
+
|
|
53
|
+
def compile(self, ttFont):
|
|
54
|
+
if ttFont.recalcBBoxes and (
|
|
55
|
+
ttFont.isLoaded("glyf")
|
|
56
|
+
or ttFont.isLoaded("CFF ")
|
|
57
|
+
or ttFont.isLoaded("CFF2")
|
|
58
|
+
):
|
|
59
|
+
self.recalc(ttFont)
|
|
60
|
+
self.tableVersion = fi2ve(self.tableVersion)
|
|
61
|
+
return sstruct.pack(vheaFormat, self)
|
|
62
|
+
|
|
63
|
+
def recalc(self, ttFont):
|
|
64
|
+
if "vmtx" not in ttFont:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
vmtxTable = ttFont["vmtx"]
|
|
68
|
+
self.advanceHeightMax = max(adv for adv, _ in vmtxTable.metrics.values())
|
|
69
|
+
|
|
70
|
+
boundsHeightDict = {}
|
|
71
|
+
if "glyf" in ttFont:
|
|
72
|
+
glyfTable = ttFont["glyf"]
|
|
73
|
+
for name in ttFont.getGlyphOrder():
|
|
74
|
+
g = glyfTable[name]
|
|
75
|
+
if g.numberOfContours == 0:
|
|
76
|
+
continue
|
|
77
|
+
if g.numberOfContours < 0 and not hasattr(g, "yMax"):
|
|
78
|
+
# Composite glyph without extents set.
|
|
79
|
+
# Calculate those.
|
|
80
|
+
g.recalcBounds(glyfTable)
|
|
81
|
+
boundsHeightDict[name] = g.yMax - g.yMin
|
|
82
|
+
elif "CFF " in ttFont or "CFF2" in ttFont:
|
|
83
|
+
if "CFF " in ttFont:
|
|
84
|
+
topDict = ttFont["CFF "].cff.topDictIndex[0]
|
|
85
|
+
else:
|
|
86
|
+
topDict = ttFont["CFF2"].cff.topDictIndex[0]
|
|
87
|
+
charStrings = topDict.CharStrings
|
|
88
|
+
for name in ttFont.getGlyphOrder():
|
|
89
|
+
cs = charStrings[name]
|
|
90
|
+
bounds = cs.calcBounds(charStrings)
|
|
91
|
+
if bounds is not None:
|
|
92
|
+
boundsHeightDict[name] = int(
|
|
93
|
+
math.ceil(bounds[3]) - math.floor(bounds[1])
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if boundsHeightDict:
|
|
97
|
+
minTopSideBearing = float("inf")
|
|
98
|
+
minBottomSideBearing = float("inf")
|
|
99
|
+
yMaxExtent = -float("inf")
|
|
100
|
+
for name, boundsHeight in boundsHeightDict.items():
|
|
101
|
+
advanceHeight, tsb = vmtxTable[name]
|
|
102
|
+
bsb = advanceHeight - tsb - boundsHeight
|
|
103
|
+
extent = tsb + boundsHeight
|
|
104
|
+
minTopSideBearing = min(minTopSideBearing, tsb)
|
|
105
|
+
minBottomSideBearing = min(minBottomSideBearing, bsb)
|
|
106
|
+
yMaxExtent = max(yMaxExtent, extent)
|
|
107
|
+
self.minTopSideBearing = minTopSideBearing
|
|
108
|
+
self.minBottomSideBearing = minBottomSideBearing
|
|
109
|
+
self.yMaxExtent = yMaxExtent
|
|
110
|
+
|
|
111
|
+
else: # No glyph has outlines.
|
|
112
|
+
self.minTopSideBearing = 0
|
|
113
|
+
self.minBottomSideBearing = 0
|
|
114
|
+
self.yMaxExtent = 0
|
|
115
|
+
|
|
116
|
+
def toXML(self, writer, ttFont):
|
|
117
|
+
formatstring, names, fixes = sstruct.getformat(vheaFormat)
|
|
118
|
+
for name in names:
|
|
119
|
+
value = getattr(self, name)
|
|
120
|
+
if name == "tableVersion":
|
|
121
|
+
value = fi2ve(value)
|
|
122
|
+
value = "0x%08x" % value
|
|
123
|
+
writer.simpletag(name, value=value)
|
|
124
|
+
writer.newline()
|
|
125
|
+
|
|
126
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
127
|
+
if name == "tableVersion":
|
|
128
|
+
setattr(self, name, ve2fi(attrs["value"]))
|
|
129
|
+
return
|
|
130
|
+
setattr(self, name, safeEval(attrs["value"]))
|
|
131
|
+
|
|
132
|
+
# reserved0 is caretOffset for legacy reasons
|
|
133
|
+
@property
|
|
134
|
+
def reserved0(self):
|
|
135
|
+
return self.caretOffset
|
|
136
|
+
|
|
137
|
+
@reserved0.setter
|
|
138
|
+
def reserved0(self, value):
|
|
139
|
+
self.caretOffset = value
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from fontTools import ttLib
|
|
2
|
+
|
|
3
|
+
superclass = ttLib.getTableClass("hmtx")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class table__v_m_t_x(superclass):
|
|
7
|
+
"""Vertical Metrics table
|
|
8
|
+
|
|
9
|
+
The ``vmtx`` table contains per-glyph metrics for the glyphs in a
|
|
10
|
+
``glyf``, ``CFF ``, or ``CFF2`` table, as needed for vertical text
|
|
11
|
+
layout.
|
|
12
|
+
|
|
13
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/vmtx
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
headerTag = "vhea"
|
|
17
|
+
advanceName = "height"
|
|
18
|
+
sideBearingName = "tsb"
|
|
19
|
+
numberOfMetricsName = "numberOfVMetrics"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from fontTools.misc.textTools import strjoin, tobytes, tostr
|
|
2
|
+
from . import DefaultTable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class asciiTable(DefaultTable.DefaultTable):
|
|
6
|
+
def toXML(self, writer, ttFont):
|
|
7
|
+
data = tostr(self.data)
|
|
8
|
+
# removing null bytes. XXX needed??
|
|
9
|
+
data = data.split("\0")
|
|
10
|
+
data = strjoin(data)
|
|
11
|
+
writer.begintag("source")
|
|
12
|
+
writer.newline()
|
|
13
|
+
writer.write_noindent(data)
|
|
14
|
+
writer.newline()
|
|
15
|
+
writer.endtag("source")
|
|
16
|
+
writer.newline()
|
|
17
|
+
|
|
18
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
19
|
+
lines = strjoin(content).split("\n")
|
|
20
|
+
self.data = tobytes("\n".join(lines[1:-1]))
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import struct, warnings
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
import lz4
|
|
5
|
+
except ImportError:
|
|
6
|
+
lz4 = None
|
|
7
|
+
else:
|
|
8
|
+
import lz4.block
|
|
9
|
+
|
|
10
|
+
# old scheme for VERSION < 0.9 otherwise use lz4.block
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def decompress(data):
|
|
14
|
+
(compression,) = struct.unpack(">L", data[4:8])
|
|
15
|
+
scheme = compression >> 27
|
|
16
|
+
size = compression & 0x07FFFFFF
|
|
17
|
+
if scheme == 0:
|
|
18
|
+
pass
|
|
19
|
+
elif scheme == 1 and lz4:
|
|
20
|
+
res = lz4.block.decompress(struct.pack("<L", size) + data[8:])
|
|
21
|
+
if len(res) != size:
|
|
22
|
+
warnings.warn("Table decompression failed.")
|
|
23
|
+
else:
|
|
24
|
+
data = res
|
|
25
|
+
else:
|
|
26
|
+
warnings.warn("Table is compressed with an unsupported compression scheme")
|
|
27
|
+
return (data, scheme)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def compress(scheme, data):
|
|
31
|
+
hdr = data[:4] + struct.pack(">L", (scheme << 27) + (len(data) & 0x07FFFFFF))
|
|
32
|
+
if scheme == 0:
|
|
33
|
+
return data
|
|
34
|
+
elif scheme == 1 and lz4:
|
|
35
|
+
res = lz4.block.compress(
|
|
36
|
+
data, mode="high_compression", compression=16, store_size=False
|
|
37
|
+
)
|
|
38
|
+
return hdr + res
|
|
39
|
+
else:
|
|
40
|
+
warnings.warn("Table failed to compress by unsupported compression scheme")
|
|
41
|
+
return data
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _entries(attrs, sameval):
|
|
45
|
+
ak = 0
|
|
46
|
+
vals = []
|
|
47
|
+
lastv = 0
|
|
48
|
+
for k, v in attrs:
|
|
49
|
+
if len(vals) and (k != ak + 1 or (sameval and v != lastv)):
|
|
50
|
+
yield (ak - len(vals) + 1, len(vals), vals)
|
|
51
|
+
vals = []
|
|
52
|
+
ak = k
|
|
53
|
+
vals.append(v)
|
|
54
|
+
lastv = v
|
|
55
|
+
yield (ak - len(vals) + 1, len(vals), vals)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def entries(attributes, sameval=False):
|
|
59
|
+
g = _entries(sorted(attributes.items(), key=lambda x: int(x[0])), sameval)
|
|
60
|
+
return g
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def bininfo(num, size=1):
|
|
64
|
+
if num == 0:
|
|
65
|
+
return struct.pack(">4H", 0, 0, 0, 0)
|
|
66
|
+
srange = 1
|
|
67
|
+
select = 0
|
|
68
|
+
while srange <= num:
|
|
69
|
+
srange *= 2
|
|
70
|
+
select += 1
|
|
71
|
+
select -= 1
|
|
72
|
+
srange //= 2
|
|
73
|
+
srange *= size
|
|
74
|
+
shift = num * size - srange
|
|
75
|
+
return struct.pack(">4H", num, srange, select, shift)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def num2tag(n):
|
|
79
|
+
if n < 0x200000:
|
|
80
|
+
return str(n)
|
|
81
|
+
else:
|
|
82
|
+
return (
|
|
83
|
+
struct.unpack("4s", struct.pack(">L", n))[0].replace(b"\000", b"").decode()
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def tag2num(n):
|
|
88
|
+
try:
|
|
89
|
+
return int(n)
|
|
90
|
+
except ValueError:
|
|
91
|
+
n = (n + " ")[:4]
|
|
92
|
+
return struct.unpack(">L", n.encode("ascii"))[0]
|