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,147 @@
|
|
|
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
|
+
hheaFormat = """
|
|
12
|
+
> # big endian
|
|
13
|
+
tableVersion: L
|
|
14
|
+
ascent: h
|
|
15
|
+
descent: h
|
|
16
|
+
lineGap: h
|
|
17
|
+
advanceWidthMax: H
|
|
18
|
+
minLeftSideBearing: h
|
|
19
|
+
minRightSideBearing: h
|
|
20
|
+
xMaxExtent: h
|
|
21
|
+
caretSlopeRise: h
|
|
22
|
+
caretSlopeRun: h
|
|
23
|
+
caretOffset: h
|
|
24
|
+
reserved0: h
|
|
25
|
+
reserved1: h
|
|
26
|
+
reserved2: h
|
|
27
|
+
reserved3: h
|
|
28
|
+
metricDataFormat: h
|
|
29
|
+
numberOfHMetrics: H
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class table__h_h_e_a(DefaultTable.DefaultTable):
|
|
34
|
+
"""Horizontal Header table
|
|
35
|
+
|
|
36
|
+
The ``hhea`` table contains information needed during horizontal
|
|
37
|
+
text layout.
|
|
38
|
+
|
|
39
|
+
.. note::
|
|
40
|
+
This converter class is kept in sync with the :class:`._v_h_e_a.table__v_h_e_a`
|
|
41
|
+
table constructor.
|
|
42
|
+
|
|
43
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/hhea
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Note: Keep in sync with table__v_h_e_a
|
|
47
|
+
|
|
48
|
+
dependencies = ["hmtx", "glyf", "CFF ", "CFF2"]
|
|
49
|
+
|
|
50
|
+
# OpenType spec renamed these, add aliases for compatibility
|
|
51
|
+
@property
|
|
52
|
+
def ascender(self):
|
|
53
|
+
return self.ascent
|
|
54
|
+
|
|
55
|
+
@ascender.setter
|
|
56
|
+
def ascender(self, value):
|
|
57
|
+
self.ascent = value
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def descender(self):
|
|
61
|
+
return self.descent
|
|
62
|
+
|
|
63
|
+
@descender.setter
|
|
64
|
+
def descender(self, value):
|
|
65
|
+
self.descent = value
|
|
66
|
+
|
|
67
|
+
def decompile(self, data, ttFont):
|
|
68
|
+
sstruct.unpack(hheaFormat, data, self)
|
|
69
|
+
|
|
70
|
+
def compile(self, ttFont):
|
|
71
|
+
if ttFont.recalcBBoxes and (
|
|
72
|
+
ttFont.isLoaded("glyf")
|
|
73
|
+
or ttFont.isLoaded("CFF ")
|
|
74
|
+
or ttFont.isLoaded("CFF2")
|
|
75
|
+
):
|
|
76
|
+
self.recalc(ttFont)
|
|
77
|
+
self.tableVersion = fi2ve(self.tableVersion)
|
|
78
|
+
return sstruct.pack(hheaFormat, self)
|
|
79
|
+
|
|
80
|
+
def recalc(self, ttFont):
|
|
81
|
+
if "hmtx" not in ttFont:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
hmtxTable = ttFont["hmtx"]
|
|
85
|
+
self.advanceWidthMax = max(adv for adv, _ in hmtxTable.metrics.values())
|
|
86
|
+
|
|
87
|
+
boundsWidthDict = {}
|
|
88
|
+
if "glyf" in ttFont:
|
|
89
|
+
glyfTable = ttFont["glyf"]
|
|
90
|
+
for name in ttFont.getGlyphOrder():
|
|
91
|
+
g = glyfTable[name]
|
|
92
|
+
if g.numberOfContours == 0:
|
|
93
|
+
continue
|
|
94
|
+
if g.numberOfContours < 0 and not hasattr(g, "xMax"):
|
|
95
|
+
# Composite glyph without extents set.
|
|
96
|
+
# Calculate those.
|
|
97
|
+
g.recalcBounds(glyfTable)
|
|
98
|
+
boundsWidthDict[name] = g.xMax - g.xMin
|
|
99
|
+
elif "CFF " in ttFont or "CFF2" in ttFont:
|
|
100
|
+
if "CFF " in ttFont:
|
|
101
|
+
topDict = ttFont["CFF "].cff.topDictIndex[0]
|
|
102
|
+
else:
|
|
103
|
+
topDict = ttFont["CFF2"].cff.topDictIndex[0]
|
|
104
|
+
charStrings = topDict.CharStrings
|
|
105
|
+
for name in ttFont.getGlyphOrder():
|
|
106
|
+
cs = charStrings[name]
|
|
107
|
+
bounds = cs.calcBounds(charStrings)
|
|
108
|
+
if bounds is not None:
|
|
109
|
+
boundsWidthDict[name] = int(
|
|
110
|
+
math.ceil(bounds[2]) - math.floor(bounds[0])
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if boundsWidthDict:
|
|
114
|
+
minLeftSideBearing = float("inf")
|
|
115
|
+
minRightSideBearing = float("inf")
|
|
116
|
+
xMaxExtent = -float("inf")
|
|
117
|
+
for name, boundsWidth in boundsWidthDict.items():
|
|
118
|
+
advanceWidth, lsb = hmtxTable[name]
|
|
119
|
+
rsb = advanceWidth - lsb - boundsWidth
|
|
120
|
+
extent = lsb + boundsWidth
|
|
121
|
+
minLeftSideBearing = min(minLeftSideBearing, lsb)
|
|
122
|
+
minRightSideBearing = min(minRightSideBearing, rsb)
|
|
123
|
+
xMaxExtent = max(xMaxExtent, extent)
|
|
124
|
+
self.minLeftSideBearing = minLeftSideBearing
|
|
125
|
+
self.minRightSideBearing = minRightSideBearing
|
|
126
|
+
self.xMaxExtent = xMaxExtent
|
|
127
|
+
|
|
128
|
+
else: # No glyph has outlines.
|
|
129
|
+
self.minLeftSideBearing = 0
|
|
130
|
+
self.minRightSideBearing = 0
|
|
131
|
+
self.xMaxExtent = 0
|
|
132
|
+
|
|
133
|
+
def toXML(self, writer, ttFont):
|
|
134
|
+
formatstring, names, fixes = sstruct.getformat(hheaFormat)
|
|
135
|
+
for name in names:
|
|
136
|
+
value = getattr(self, name)
|
|
137
|
+
if name == "tableVersion":
|
|
138
|
+
value = fi2ve(value)
|
|
139
|
+
value = "0x%08x" % value
|
|
140
|
+
writer.simpletag(name, value=value)
|
|
141
|
+
writer.newline()
|
|
142
|
+
|
|
143
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
144
|
+
if name == "tableVersion":
|
|
145
|
+
setattr(self, name, ve2fi(attrs["value"]))
|
|
146
|
+
return
|
|
147
|
+
setattr(self, name, safeEval(attrs["value"]))
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from fontTools.misc.roundTools import otRound
|
|
2
|
+
from fontTools import ttLib
|
|
3
|
+
from fontTools.misc.textTools import safeEval
|
|
4
|
+
from . import DefaultTable
|
|
5
|
+
import sys
|
|
6
|
+
import struct
|
|
7
|
+
import array
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
log = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class table__h_m_t_x(DefaultTable.DefaultTable):
|
|
15
|
+
"""Horizontal Metrics table
|
|
16
|
+
|
|
17
|
+
The ``hmtx`` table contains per-glyph metrics for the glyphs in a
|
|
18
|
+
``glyf``, ``CFF ``, or ``CFF2`` table, as needed for horizontal text
|
|
19
|
+
layout.
|
|
20
|
+
|
|
21
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/hmtx
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
headerTag = "hhea"
|
|
25
|
+
advanceName = "width"
|
|
26
|
+
sideBearingName = "lsb"
|
|
27
|
+
numberOfMetricsName = "numberOfHMetrics"
|
|
28
|
+
longMetricFormat = "Hh"
|
|
29
|
+
|
|
30
|
+
def decompile(self, data, ttFont):
|
|
31
|
+
numGlyphs = ttFont["maxp"].numGlyphs
|
|
32
|
+
headerTable = ttFont.get(self.headerTag)
|
|
33
|
+
if headerTable is not None:
|
|
34
|
+
numberOfMetrics = int(getattr(headerTable, self.numberOfMetricsName))
|
|
35
|
+
else:
|
|
36
|
+
numberOfMetrics = numGlyphs
|
|
37
|
+
if numberOfMetrics > numGlyphs:
|
|
38
|
+
log.warning(
|
|
39
|
+
"The %s.%s exceeds the maxp.numGlyphs"
|
|
40
|
+
% (self.headerTag, self.numberOfMetricsName)
|
|
41
|
+
)
|
|
42
|
+
numberOfMetrics = numGlyphs
|
|
43
|
+
numberOfSideBearings = numGlyphs - numberOfMetrics
|
|
44
|
+
tableSize = 4 * numberOfMetrics + 2 * numberOfSideBearings
|
|
45
|
+
if len(data) < tableSize:
|
|
46
|
+
raise ttLib.TTLibError(
|
|
47
|
+
f"not enough '{self.tableTag}' table data: "
|
|
48
|
+
f"expected {tableSize} bytes, got {len(data)}"
|
|
49
|
+
)
|
|
50
|
+
# Note: advanceWidth is unsigned, but some font editors might
|
|
51
|
+
# read/write as signed. We can't be sure whether it was a mistake
|
|
52
|
+
# or not, so we read as unsigned but also issue a warning...
|
|
53
|
+
metricsFmt = ">" + self.longMetricFormat * numberOfMetrics
|
|
54
|
+
metrics = struct.unpack(metricsFmt, data[: 4 * numberOfMetrics])
|
|
55
|
+
data = data[4 * numberOfMetrics :]
|
|
56
|
+
sideBearings = array.array("h", data[: 2 * numberOfSideBearings])
|
|
57
|
+
data = data[2 * numberOfSideBearings :]
|
|
58
|
+
|
|
59
|
+
if sys.byteorder != "big":
|
|
60
|
+
sideBearings.byteswap()
|
|
61
|
+
if data:
|
|
62
|
+
log.warning("too much '%s' table data" % self.tableTag)
|
|
63
|
+
self.metrics = {}
|
|
64
|
+
glyphOrder = ttFont.getGlyphOrder()
|
|
65
|
+
for i in range(numberOfMetrics):
|
|
66
|
+
glyphName = glyphOrder[i]
|
|
67
|
+
advanceWidth, lsb = metrics[i * 2 : i * 2 + 2]
|
|
68
|
+
if advanceWidth > 32767:
|
|
69
|
+
log.warning(
|
|
70
|
+
"Glyph %r has a huge advance %s (%d); is it intentional or "
|
|
71
|
+
"an (invalid) negative value?",
|
|
72
|
+
glyphName,
|
|
73
|
+
self.advanceName,
|
|
74
|
+
advanceWidth,
|
|
75
|
+
)
|
|
76
|
+
self.metrics[glyphName] = (advanceWidth, lsb)
|
|
77
|
+
lastAdvance = metrics[-2]
|
|
78
|
+
for i in range(numberOfSideBearings):
|
|
79
|
+
glyphName = glyphOrder[i + numberOfMetrics]
|
|
80
|
+
self.metrics[glyphName] = (lastAdvance, sideBearings[i])
|
|
81
|
+
|
|
82
|
+
def compile(self, ttFont):
|
|
83
|
+
metrics = []
|
|
84
|
+
hasNegativeAdvances = False
|
|
85
|
+
for glyphName in ttFont.getGlyphOrder():
|
|
86
|
+
advanceWidth, sideBearing = self.metrics[glyphName]
|
|
87
|
+
if advanceWidth < 0:
|
|
88
|
+
log.error(
|
|
89
|
+
"Glyph %r has negative advance %s" % (glyphName, self.advanceName)
|
|
90
|
+
)
|
|
91
|
+
hasNegativeAdvances = True
|
|
92
|
+
metrics.append([advanceWidth, sideBearing])
|
|
93
|
+
|
|
94
|
+
headerTable = ttFont.get(self.headerTag)
|
|
95
|
+
if headerTable is not None:
|
|
96
|
+
lastAdvance = metrics[-1][0]
|
|
97
|
+
lastIndex = len(metrics)
|
|
98
|
+
while metrics[lastIndex - 2][0] == lastAdvance:
|
|
99
|
+
lastIndex -= 1
|
|
100
|
+
if lastIndex <= 1:
|
|
101
|
+
# all advances are equal
|
|
102
|
+
lastIndex = 1
|
|
103
|
+
break
|
|
104
|
+
additionalMetrics = metrics[lastIndex:]
|
|
105
|
+
additionalMetrics = [otRound(sb) for _, sb in additionalMetrics]
|
|
106
|
+
metrics = metrics[:lastIndex]
|
|
107
|
+
numberOfMetrics = len(metrics)
|
|
108
|
+
setattr(headerTable, self.numberOfMetricsName, numberOfMetrics)
|
|
109
|
+
else:
|
|
110
|
+
# no hhea/vhea, can't store numberOfMetrics; assume == numGlyphs
|
|
111
|
+
numberOfMetrics = ttFont["maxp"].numGlyphs
|
|
112
|
+
additionalMetrics = []
|
|
113
|
+
|
|
114
|
+
allMetrics = []
|
|
115
|
+
for advance, sb in metrics:
|
|
116
|
+
allMetrics.extend([otRound(advance), otRound(sb)])
|
|
117
|
+
metricsFmt = ">" + self.longMetricFormat * numberOfMetrics
|
|
118
|
+
try:
|
|
119
|
+
data = struct.pack(metricsFmt, *allMetrics)
|
|
120
|
+
except struct.error as e:
|
|
121
|
+
if "out of range" in str(e) and hasNegativeAdvances:
|
|
122
|
+
raise ttLib.TTLibError(
|
|
123
|
+
"'%s' table can't contain negative advance %ss"
|
|
124
|
+
% (self.tableTag, self.advanceName)
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
raise
|
|
128
|
+
additionalMetrics = array.array("h", additionalMetrics)
|
|
129
|
+
if sys.byteorder != "big":
|
|
130
|
+
additionalMetrics.byteswap()
|
|
131
|
+
data = data + additionalMetrics.tobytes()
|
|
132
|
+
return data
|
|
133
|
+
|
|
134
|
+
def toXML(self, writer, ttFont):
|
|
135
|
+
names = sorted(self.metrics.keys())
|
|
136
|
+
for glyphName in names:
|
|
137
|
+
advance, sb = self.metrics[glyphName]
|
|
138
|
+
writer.simpletag(
|
|
139
|
+
"mtx",
|
|
140
|
+
[
|
|
141
|
+
("name", glyphName),
|
|
142
|
+
(self.advanceName, advance),
|
|
143
|
+
(self.sideBearingName, sb),
|
|
144
|
+
],
|
|
145
|
+
)
|
|
146
|
+
writer.newline()
|
|
147
|
+
|
|
148
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
149
|
+
if not hasattr(self, "metrics"):
|
|
150
|
+
self.metrics = {}
|
|
151
|
+
if name == "mtx":
|
|
152
|
+
self.metrics[attrs["name"]] = (
|
|
153
|
+
safeEval(attrs[self.advanceName]),
|
|
154
|
+
safeEval(attrs[self.sideBearingName]),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def __delitem__(self, glyphName):
|
|
158
|
+
del self.metrics[glyphName]
|
|
159
|
+
|
|
160
|
+
def __getitem__(self, glyphName):
|
|
161
|
+
return self.metrics[glyphName]
|
|
162
|
+
|
|
163
|
+
def __setitem__(self, glyphName, advance_sb_pair):
|
|
164
|
+
self.metrics[glyphName] = tuple(advance_sb_pair)
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
from fontTools.ttLib import getSearchRange
|
|
2
|
+
from fontTools.misc.textTools import safeEval, readHex
|
|
3
|
+
from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
|
|
4
|
+
from . import DefaultTable
|
|
5
|
+
import struct
|
|
6
|
+
import sys
|
|
7
|
+
import array
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
log = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class table__k_e_r_n(DefaultTable.DefaultTable):
|
|
15
|
+
"""Kerning table
|
|
16
|
+
|
|
17
|
+
The ``kern`` table contains values that contextually adjust the inter-glyph
|
|
18
|
+
spacing for the glyphs in a ``glyf`` table.
|
|
19
|
+
|
|
20
|
+
Note that similar contextual spacing adjustments can also be stored
|
|
21
|
+
in the "kern" feature of a ``GPOS`` table.
|
|
22
|
+
|
|
23
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/kern
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def getkern(self, format):
|
|
27
|
+
for subtable in self.kernTables:
|
|
28
|
+
if subtable.format == format:
|
|
29
|
+
return subtable
|
|
30
|
+
return None # not found
|
|
31
|
+
|
|
32
|
+
def decompile(self, data, ttFont):
|
|
33
|
+
version, nTables = struct.unpack(">HH", data[:4])
|
|
34
|
+
apple = False
|
|
35
|
+
if (len(data) >= 8) and (version == 1):
|
|
36
|
+
# AAT Apple's "new" format. Hm.
|
|
37
|
+
version, nTables = struct.unpack(">LL", data[:8])
|
|
38
|
+
self.version = fi2fl(version, 16)
|
|
39
|
+
data = data[8:]
|
|
40
|
+
apple = True
|
|
41
|
+
else:
|
|
42
|
+
self.version = version
|
|
43
|
+
data = data[4:]
|
|
44
|
+
self.kernTables = []
|
|
45
|
+
for i in range(nTables):
|
|
46
|
+
if self.version == 1.0:
|
|
47
|
+
# Apple
|
|
48
|
+
length, coverage, subtableFormat = struct.unpack(">LBB", data[:6])
|
|
49
|
+
else:
|
|
50
|
+
# in OpenType spec the "version" field refers to the common
|
|
51
|
+
# subtable header; the actual subtable format is stored in
|
|
52
|
+
# the 8-15 mask bits of "coverage" field.
|
|
53
|
+
# This "version" is always 0 so we ignore it here
|
|
54
|
+
_, length, subtableFormat, coverage = struct.unpack(">HHBB", data[:6])
|
|
55
|
+
if nTables == 1 and subtableFormat == 0:
|
|
56
|
+
# The "length" value is ignored since some fonts
|
|
57
|
+
# (like OpenSans and Calibri) have a subtable larger than
|
|
58
|
+
# its value.
|
|
59
|
+
(nPairs,) = struct.unpack(">H", data[6:8])
|
|
60
|
+
calculated_length = (nPairs * 6) + 14
|
|
61
|
+
if length != calculated_length:
|
|
62
|
+
log.warning(
|
|
63
|
+
"'kern' subtable longer than defined: "
|
|
64
|
+
"%d bytes instead of %d bytes" % (calculated_length, length)
|
|
65
|
+
)
|
|
66
|
+
length = calculated_length
|
|
67
|
+
if subtableFormat not in kern_classes:
|
|
68
|
+
subtable = KernTable_format_unkown(subtableFormat)
|
|
69
|
+
else:
|
|
70
|
+
subtable = kern_classes[subtableFormat](apple)
|
|
71
|
+
subtable.decompile(data[:length], ttFont)
|
|
72
|
+
self.kernTables.append(subtable)
|
|
73
|
+
data = data[length:]
|
|
74
|
+
|
|
75
|
+
def compile(self, ttFont):
|
|
76
|
+
if hasattr(self, "kernTables"):
|
|
77
|
+
nTables = len(self.kernTables)
|
|
78
|
+
else:
|
|
79
|
+
nTables = 0
|
|
80
|
+
if self.version == 1.0:
|
|
81
|
+
# AAT Apple's "new" format.
|
|
82
|
+
data = struct.pack(">LL", fl2fi(self.version, 16), nTables)
|
|
83
|
+
else:
|
|
84
|
+
data = struct.pack(">HH", self.version, nTables)
|
|
85
|
+
if hasattr(self, "kernTables"):
|
|
86
|
+
for subtable in self.kernTables:
|
|
87
|
+
data = data + subtable.compile(ttFont)
|
|
88
|
+
return data
|
|
89
|
+
|
|
90
|
+
def toXML(self, writer, ttFont):
|
|
91
|
+
writer.simpletag("version", value=self.version)
|
|
92
|
+
writer.newline()
|
|
93
|
+
for subtable in self.kernTables:
|
|
94
|
+
subtable.toXML(writer, ttFont)
|
|
95
|
+
|
|
96
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
97
|
+
if name == "version":
|
|
98
|
+
self.version = safeEval(attrs["value"])
|
|
99
|
+
return
|
|
100
|
+
if name != "kernsubtable":
|
|
101
|
+
return
|
|
102
|
+
if not hasattr(self, "kernTables"):
|
|
103
|
+
self.kernTables = []
|
|
104
|
+
format = safeEval(attrs["format"])
|
|
105
|
+
if format not in kern_classes:
|
|
106
|
+
subtable = KernTable_format_unkown(format)
|
|
107
|
+
else:
|
|
108
|
+
apple = self.version == 1.0
|
|
109
|
+
subtable = kern_classes[format](apple)
|
|
110
|
+
self.kernTables.append(subtable)
|
|
111
|
+
subtable.fromXML(name, attrs, content, ttFont)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class KernTable_format_0(object):
|
|
115
|
+
# 'version' is kept for backward compatibility
|
|
116
|
+
version = format = 0
|
|
117
|
+
|
|
118
|
+
def __init__(self, apple=False):
|
|
119
|
+
self.apple = apple
|
|
120
|
+
|
|
121
|
+
def decompile(self, data, ttFont):
|
|
122
|
+
if not self.apple:
|
|
123
|
+
version, length, subtableFormat, coverage = struct.unpack(">HHBB", data[:6])
|
|
124
|
+
if version != 0:
|
|
125
|
+
from fontTools.ttLib import TTLibError
|
|
126
|
+
|
|
127
|
+
raise TTLibError("unsupported kern subtable version: %d" % version)
|
|
128
|
+
tupleIndex = None
|
|
129
|
+
# Should we also assert length == len(data)?
|
|
130
|
+
data = data[6:]
|
|
131
|
+
else:
|
|
132
|
+
length, coverage, subtableFormat, tupleIndex = struct.unpack(
|
|
133
|
+
">LBBH", data[:8]
|
|
134
|
+
)
|
|
135
|
+
data = data[8:]
|
|
136
|
+
assert self.format == subtableFormat, "unsupported format"
|
|
137
|
+
self.coverage = coverage
|
|
138
|
+
self.tupleIndex = tupleIndex
|
|
139
|
+
|
|
140
|
+
self.kernTable = kernTable = {}
|
|
141
|
+
|
|
142
|
+
nPairs, searchRange, entrySelector, rangeShift = struct.unpack(
|
|
143
|
+
">HHHH", data[:8]
|
|
144
|
+
)
|
|
145
|
+
data = data[8:]
|
|
146
|
+
|
|
147
|
+
datas = array.array("H", data[: 6 * nPairs])
|
|
148
|
+
if sys.byteorder != "big":
|
|
149
|
+
datas.byteswap()
|
|
150
|
+
it = iter(datas)
|
|
151
|
+
glyphOrder = ttFont.getGlyphOrder()
|
|
152
|
+
for k in range(nPairs):
|
|
153
|
+
left, right, value = next(it), next(it), next(it)
|
|
154
|
+
if value >= 32768:
|
|
155
|
+
value -= 65536
|
|
156
|
+
try:
|
|
157
|
+
kernTable[(glyphOrder[left], glyphOrder[right])] = value
|
|
158
|
+
except IndexError:
|
|
159
|
+
# Slower, but will not throw an IndexError on an invalid
|
|
160
|
+
# glyph id.
|
|
161
|
+
kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = (
|
|
162
|
+
value
|
|
163
|
+
)
|
|
164
|
+
if len(data) > 6 * nPairs + 4: # Ignore up to 4 bytes excess
|
|
165
|
+
log.warning(
|
|
166
|
+
"excess data in 'kern' subtable: %d bytes", len(data) - 6 * nPairs
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def compile(self, ttFont):
|
|
170
|
+
nPairs = min(len(self.kernTable), 0xFFFF)
|
|
171
|
+
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
|
|
172
|
+
searchRange &= 0xFFFF
|
|
173
|
+
entrySelector = min(entrySelector, 0xFFFF)
|
|
174
|
+
rangeShift = min(rangeShift, 0xFFFF)
|
|
175
|
+
data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
|
176
|
+
|
|
177
|
+
# yeehee! (I mean, turn names into indices)
|
|
178
|
+
try:
|
|
179
|
+
reverseOrder = ttFont.getReverseGlyphMap()
|
|
180
|
+
kernTable = sorted(
|
|
181
|
+
(reverseOrder[left], reverseOrder[right], value)
|
|
182
|
+
for ((left, right), value) in self.kernTable.items()
|
|
183
|
+
)
|
|
184
|
+
except KeyError:
|
|
185
|
+
# Slower, but will not throw KeyError on invalid glyph id.
|
|
186
|
+
getGlyphID = ttFont.getGlyphID
|
|
187
|
+
kernTable = sorted(
|
|
188
|
+
(getGlyphID(left), getGlyphID(right), value)
|
|
189
|
+
for ((left, right), value) in self.kernTable.items()
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
for left, right, value in kernTable:
|
|
193
|
+
data = data + struct.pack(">HHh", left, right, value)
|
|
194
|
+
|
|
195
|
+
if not self.apple:
|
|
196
|
+
version = 0
|
|
197
|
+
length = len(data) + 6
|
|
198
|
+
if length >= 0x10000:
|
|
199
|
+
log.warning(
|
|
200
|
+
'"kern" subtable overflow, '
|
|
201
|
+
"truncating length value while preserving pairs."
|
|
202
|
+
)
|
|
203
|
+
length &= 0xFFFF
|
|
204
|
+
header = struct.pack(">HHBB", version, length, self.format, self.coverage)
|
|
205
|
+
else:
|
|
206
|
+
if self.tupleIndex is None:
|
|
207
|
+
# sensible default when compiling a TTX from an old fonttools
|
|
208
|
+
# or when inserting a Windows-style format 0 subtable into an
|
|
209
|
+
# Apple version=1.0 kern table
|
|
210
|
+
log.warning("'tupleIndex' is None; default to 0")
|
|
211
|
+
self.tupleIndex = 0
|
|
212
|
+
length = len(data) + 8
|
|
213
|
+
header = struct.pack(
|
|
214
|
+
">LBBH", length, self.coverage, self.format, self.tupleIndex
|
|
215
|
+
)
|
|
216
|
+
return header + data
|
|
217
|
+
|
|
218
|
+
def toXML(self, writer, ttFont):
|
|
219
|
+
attrs = dict(coverage=self.coverage, format=self.format)
|
|
220
|
+
if self.apple:
|
|
221
|
+
if self.tupleIndex is None:
|
|
222
|
+
log.warning("'tupleIndex' is None; default to 0")
|
|
223
|
+
attrs["tupleIndex"] = 0
|
|
224
|
+
else:
|
|
225
|
+
attrs["tupleIndex"] = self.tupleIndex
|
|
226
|
+
writer.begintag("kernsubtable", **attrs)
|
|
227
|
+
writer.newline()
|
|
228
|
+
items = sorted(self.kernTable.items())
|
|
229
|
+
for (left, right), value in items:
|
|
230
|
+
writer.simpletag("pair", [("l", left), ("r", right), ("v", value)])
|
|
231
|
+
writer.newline()
|
|
232
|
+
writer.endtag("kernsubtable")
|
|
233
|
+
writer.newline()
|
|
234
|
+
|
|
235
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
236
|
+
self.coverage = safeEval(attrs["coverage"])
|
|
237
|
+
subtableFormat = safeEval(attrs["format"])
|
|
238
|
+
if self.apple:
|
|
239
|
+
if "tupleIndex" in attrs:
|
|
240
|
+
self.tupleIndex = safeEval(attrs["tupleIndex"])
|
|
241
|
+
else:
|
|
242
|
+
# previous fontTools versions didn't export tupleIndex
|
|
243
|
+
log.warning("Apple kern subtable is missing 'tupleIndex' attribute")
|
|
244
|
+
self.tupleIndex = None
|
|
245
|
+
else:
|
|
246
|
+
self.tupleIndex = None
|
|
247
|
+
assert subtableFormat == self.format, "unsupported format"
|
|
248
|
+
if not hasattr(self, "kernTable"):
|
|
249
|
+
self.kernTable = {}
|
|
250
|
+
for element in content:
|
|
251
|
+
if not isinstance(element, tuple):
|
|
252
|
+
continue
|
|
253
|
+
name, attrs, content = element
|
|
254
|
+
self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"])
|
|
255
|
+
|
|
256
|
+
def __getitem__(self, pair):
|
|
257
|
+
return self.kernTable[pair]
|
|
258
|
+
|
|
259
|
+
def __setitem__(self, pair, value):
|
|
260
|
+
self.kernTable[pair] = value
|
|
261
|
+
|
|
262
|
+
def __delitem__(self, pair):
|
|
263
|
+
del self.kernTable[pair]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class KernTable_format_unkown(object):
|
|
267
|
+
def __init__(self, format):
|
|
268
|
+
self.format = format
|
|
269
|
+
|
|
270
|
+
def decompile(self, data, ttFont):
|
|
271
|
+
self.data = data
|
|
272
|
+
|
|
273
|
+
def compile(self, ttFont):
|
|
274
|
+
return self.data
|
|
275
|
+
|
|
276
|
+
def toXML(self, writer, ttFont):
|
|
277
|
+
writer.begintag("kernsubtable", format=self.format)
|
|
278
|
+
writer.newline()
|
|
279
|
+
writer.comment("unknown 'kern' subtable format")
|
|
280
|
+
writer.newline()
|
|
281
|
+
writer.dumphex(self.data)
|
|
282
|
+
writer.endtag("kernsubtable")
|
|
283
|
+
writer.newline()
|
|
284
|
+
|
|
285
|
+
def fromXML(self, name, attrs, content, ttFont):
|
|
286
|
+
self.decompile(readHex(content), ttFont)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
kern_classes = {0: KernTable_format_0}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .otBase import BaseTTXConverter
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class table__l_c_a_r(BaseTTXConverter):
|
|
5
|
+
"""Ligature Caret table
|
|
6
|
+
|
|
7
|
+
The AAT ``lcar`` table stores division points within ligatures, which applications
|
|
8
|
+
can use to position carets properly between the logical parts of the ligature.
|
|
9
|
+
|
|
10
|
+
See also https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
pass
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from . import DefaultTable
|
|
2
|
+
import sys
|
|
3
|
+
import array
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
log = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class table__l_o_c_a(DefaultTable.DefaultTable):
|
|
11
|
+
"""Index to Location table
|
|
12
|
+
|
|
13
|
+
The ``loca`` table stores the offsets in the ``glyf`` table that correspond
|
|
14
|
+
to the descriptions of each glyph. The glyphs are references by Glyph ID.
|
|
15
|
+
|
|
16
|
+
See also https://learn.microsoft.com/en-us/typography/opentype/spec/loca
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
dependencies = ["glyf"]
|
|
20
|
+
|
|
21
|
+
def decompile(self, data, ttFont):
|
|
22
|
+
longFormat = ttFont["head"].indexToLocFormat
|
|
23
|
+
if longFormat:
|
|
24
|
+
format = "I"
|
|
25
|
+
else:
|
|
26
|
+
format = "H"
|
|
27
|
+
locations = array.array(format)
|
|
28
|
+
locations.frombytes(data)
|
|
29
|
+
if sys.byteorder != "big":
|
|
30
|
+
locations.byteswap()
|
|
31
|
+
if not longFormat:
|
|
32
|
+
locations = array.array("I", (2 * l for l in locations))
|
|
33
|
+
if len(locations) < (ttFont["maxp"].numGlyphs + 1):
|
|
34
|
+
log.warning(
|
|
35
|
+
"corrupt 'loca' table, or wrong numGlyphs in 'maxp': %d %d",
|
|
36
|
+
len(locations) - 1,
|
|
37
|
+
ttFont["maxp"].numGlyphs,
|
|
38
|
+
)
|
|
39
|
+
self.locations = locations
|
|
40
|
+
|
|
41
|
+
def compile(self, ttFont):
|
|
42
|
+
try:
|
|
43
|
+
max_location = max(self.locations)
|
|
44
|
+
except AttributeError:
|
|
45
|
+
self.set([])
|
|
46
|
+
max_location = 0
|
|
47
|
+
if max_location < 0x20000 and all(l % 2 == 0 for l in self.locations):
|
|
48
|
+
locations = array.array("H")
|
|
49
|
+
for location in self.locations:
|
|
50
|
+
locations.append(location // 2)
|
|
51
|
+
ttFont["head"].indexToLocFormat = 0
|
|
52
|
+
else:
|
|
53
|
+
locations = array.array("I", self.locations)
|
|
54
|
+
ttFont["head"].indexToLocFormat = 1
|
|
55
|
+
if sys.byteorder != "big":
|
|
56
|
+
locations.byteswap()
|
|
57
|
+
return locations.tobytes()
|
|
58
|
+
|
|
59
|
+
def set(self, locations):
|
|
60
|
+
self.locations = array.array("I", locations)
|
|
61
|
+
|
|
62
|
+
def toXML(self, writer, ttFont):
|
|
63
|
+
writer.comment("The 'loca' table will be calculated by the compiler")
|
|
64
|
+
writer.newline()
|
|
65
|
+
|
|
66
|
+
def __getitem__(self, index):
|
|
67
|
+
return self.locations[index]
|
|
68
|
+
|
|
69
|
+
def __len__(self):
|
|
70
|
+
return len(self.locations)
|