fonttools 4.58.3__cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.

Potentially problematic release.


This version of fonttools might be problematic. Click here for more details.

Files changed (334) hide show
  1. fontTools/__init__.py +8 -0
  2. fontTools/__main__.py +35 -0
  3. fontTools/afmLib.py +439 -0
  4. fontTools/agl.py +5233 -0
  5. fontTools/cffLib/CFF2ToCFF.py +203 -0
  6. fontTools/cffLib/CFFToCFF2.py +305 -0
  7. fontTools/cffLib/__init__.py +3694 -0
  8. fontTools/cffLib/specializer.py +927 -0
  9. fontTools/cffLib/transforms.py +490 -0
  10. fontTools/cffLib/width.py +210 -0
  11. fontTools/colorLib/__init__.py +0 -0
  12. fontTools/colorLib/builder.py +664 -0
  13. fontTools/colorLib/errors.py +2 -0
  14. fontTools/colorLib/geometry.py +143 -0
  15. fontTools/colorLib/table_builder.py +223 -0
  16. fontTools/colorLib/unbuilder.py +81 -0
  17. fontTools/config/__init__.py +90 -0
  18. fontTools/cu2qu/__init__.py +15 -0
  19. fontTools/cu2qu/__main__.py +6 -0
  20. fontTools/cu2qu/benchmark.py +54 -0
  21. fontTools/cu2qu/cli.py +198 -0
  22. fontTools/cu2qu/cu2qu.c +15545 -0
  23. fontTools/cu2qu/cu2qu.cpython-313-aarch64-linux-gnu.so +0 -0
  24. fontTools/cu2qu/cu2qu.py +531 -0
  25. fontTools/cu2qu/errors.py +77 -0
  26. fontTools/cu2qu/ufo.py +349 -0
  27. fontTools/designspaceLib/__init__.py +3338 -0
  28. fontTools/designspaceLib/__main__.py +6 -0
  29. fontTools/designspaceLib/split.py +475 -0
  30. fontTools/designspaceLib/statNames.py +260 -0
  31. fontTools/designspaceLib/types.py +147 -0
  32. fontTools/encodings/MacRoman.py +258 -0
  33. fontTools/encodings/StandardEncoding.py +258 -0
  34. fontTools/encodings/__init__.py +1 -0
  35. fontTools/encodings/codecs.py +135 -0
  36. fontTools/feaLib/__init__.py +4 -0
  37. fontTools/feaLib/__main__.py +78 -0
  38. fontTools/feaLib/ast.py +2142 -0
  39. fontTools/feaLib/builder.py +1796 -0
  40. fontTools/feaLib/error.py +22 -0
  41. fontTools/feaLib/lexer.c +17336 -0
  42. fontTools/feaLib/lexer.cpython-313-aarch64-linux-gnu.so +0 -0
  43. fontTools/feaLib/lexer.py +287 -0
  44. fontTools/feaLib/location.py +12 -0
  45. fontTools/feaLib/lookupDebugInfo.py +12 -0
  46. fontTools/feaLib/parser.py +2379 -0
  47. fontTools/feaLib/variableScalar.py +113 -0
  48. fontTools/fontBuilder.py +1014 -0
  49. fontTools/help.py +36 -0
  50. fontTools/merge/__init__.py +248 -0
  51. fontTools/merge/__main__.py +6 -0
  52. fontTools/merge/base.py +81 -0
  53. fontTools/merge/cmap.py +173 -0
  54. fontTools/merge/layout.py +526 -0
  55. fontTools/merge/options.py +85 -0
  56. fontTools/merge/tables.py +352 -0
  57. fontTools/merge/unicode.py +78 -0
  58. fontTools/merge/util.py +143 -0
  59. fontTools/misc/__init__.py +1 -0
  60. fontTools/misc/arrayTools.py +424 -0
  61. fontTools/misc/bezierTools.c +40136 -0
  62. fontTools/misc/bezierTools.cpython-313-aarch64-linux-gnu.so +0 -0
  63. fontTools/misc/bezierTools.py +1497 -0
  64. fontTools/misc/classifyTools.py +170 -0
  65. fontTools/misc/cliTools.py +53 -0
  66. fontTools/misc/configTools.py +349 -0
  67. fontTools/misc/cython.py +27 -0
  68. fontTools/misc/dictTools.py +83 -0
  69. fontTools/misc/eexec.py +119 -0
  70. fontTools/misc/encodingTools.py +72 -0
  71. fontTools/misc/etree.py +456 -0
  72. fontTools/misc/filenames.py +245 -0
  73. fontTools/misc/fixedTools.py +253 -0
  74. fontTools/misc/intTools.py +25 -0
  75. fontTools/misc/iterTools.py +12 -0
  76. fontTools/misc/lazyTools.py +42 -0
  77. fontTools/misc/loggingTools.py +543 -0
  78. fontTools/misc/macCreatorType.py +56 -0
  79. fontTools/misc/macRes.py +261 -0
  80. fontTools/misc/plistlib/__init__.py +681 -0
  81. fontTools/misc/plistlib/py.typed +0 -0
  82. fontTools/misc/psCharStrings.py +1496 -0
  83. fontTools/misc/psLib.py +398 -0
  84. fontTools/misc/psOperators.py +572 -0
  85. fontTools/misc/py23.py +96 -0
  86. fontTools/misc/roundTools.py +110 -0
  87. fontTools/misc/sstruct.py +231 -0
  88. fontTools/misc/symfont.py +242 -0
  89. fontTools/misc/testTools.py +233 -0
  90. fontTools/misc/textTools.py +154 -0
  91. fontTools/misc/timeTools.py +88 -0
  92. fontTools/misc/transform.py +516 -0
  93. fontTools/misc/treeTools.py +45 -0
  94. fontTools/misc/vector.py +147 -0
  95. fontTools/misc/visitor.py +142 -0
  96. fontTools/misc/xmlReader.py +188 -0
  97. fontTools/misc/xmlWriter.py +204 -0
  98. fontTools/mtiLib/__init__.py +1400 -0
  99. fontTools/mtiLib/__main__.py +5 -0
  100. fontTools/otlLib/__init__.py +1 -0
  101. fontTools/otlLib/builder.py +3435 -0
  102. fontTools/otlLib/error.py +11 -0
  103. fontTools/otlLib/maxContextCalc.py +96 -0
  104. fontTools/otlLib/optimize/__init__.py +53 -0
  105. fontTools/otlLib/optimize/__main__.py +6 -0
  106. fontTools/otlLib/optimize/gpos.py +439 -0
  107. fontTools/pens/__init__.py +1 -0
  108. fontTools/pens/areaPen.py +52 -0
  109. fontTools/pens/basePen.py +475 -0
  110. fontTools/pens/boundsPen.py +98 -0
  111. fontTools/pens/cairoPen.py +26 -0
  112. fontTools/pens/cocoaPen.py +26 -0
  113. fontTools/pens/cu2quPen.py +325 -0
  114. fontTools/pens/explicitClosingLinePen.py +101 -0
  115. fontTools/pens/filterPen.py +241 -0
  116. fontTools/pens/freetypePen.py +462 -0
  117. fontTools/pens/hashPointPen.py +89 -0
  118. fontTools/pens/momentsPen.c +13459 -0
  119. fontTools/pens/momentsPen.cpython-313-aarch64-linux-gnu.so +0 -0
  120. fontTools/pens/momentsPen.py +879 -0
  121. fontTools/pens/perimeterPen.py +69 -0
  122. fontTools/pens/pointInsidePen.py +192 -0
  123. fontTools/pens/pointPen.py +609 -0
  124. fontTools/pens/qtPen.py +29 -0
  125. fontTools/pens/qu2cuPen.py +105 -0
  126. fontTools/pens/quartzPen.py +43 -0
  127. fontTools/pens/recordingPen.py +335 -0
  128. fontTools/pens/reportLabPen.py +79 -0
  129. fontTools/pens/reverseContourPen.py +96 -0
  130. fontTools/pens/roundingPen.py +130 -0
  131. fontTools/pens/statisticsPen.py +312 -0
  132. fontTools/pens/svgPathPen.py +310 -0
  133. fontTools/pens/t2CharStringPen.py +88 -0
  134. fontTools/pens/teePen.py +55 -0
  135. fontTools/pens/transformPen.py +115 -0
  136. fontTools/pens/ttGlyphPen.py +335 -0
  137. fontTools/pens/wxPen.py +29 -0
  138. fontTools/qu2cu/__init__.py +15 -0
  139. fontTools/qu2cu/__main__.py +7 -0
  140. fontTools/qu2cu/benchmark.py +56 -0
  141. fontTools/qu2cu/cli.py +125 -0
  142. fontTools/qu2cu/qu2cu.c +16738 -0
  143. fontTools/qu2cu/qu2cu.cpython-313-aarch64-linux-gnu.so +0 -0
  144. fontTools/qu2cu/qu2cu.py +405 -0
  145. fontTools/subset/__init__.py +3929 -0
  146. fontTools/subset/__main__.py +6 -0
  147. fontTools/subset/cff.py +184 -0
  148. fontTools/subset/svg.py +253 -0
  149. fontTools/subset/util.py +25 -0
  150. fontTools/svgLib/__init__.py +3 -0
  151. fontTools/svgLib/path/__init__.py +65 -0
  152. fontTools/svgLib/path/arc.py +154 -0
  153. fontTools/svgLib/path/parser.py +322 -0
  154. fontTools/svgLib/path/shapes.py +183 -0
  155. fontTools/t1Lib/__init__.py +648 -0
  156. fontTools/tfmLib.py +460 -0
  157. fontTools/ttLib/__init__.py +30 -0
  158. fontTools/ttLib/__main__.py +148 -0
  159. fontTools/ttLib/macUtils.py +54 -0
  160. fontTools/ttLib/removeOverlaps.py +393 -0
  161. fontTools/ttLib/reorderGlyphs.py +285 -0
  162. fontTools/ttLib/scaleUpem.py +436 -0
  163. fontTools/ttLib/sfnt.py +662 -0
  164. fontTools/ttLib/standardGlyphOrder.py +271 -0
  165. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  166. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  167. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  168. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  169. fontTools/ttLib/tables/C_F_F_.py +61 -0
  170. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  171. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  172. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  173. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  174. fontTools/ttLib/tables/D__e_b_g.py +35 -0
  175. fontTools/ttLib/tables/DefaultTable.py +49 -0
  176. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  177. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  178. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  179. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  180. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  181. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  182. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  183. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  184. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  185. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  186. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  187. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  188. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  189. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  190. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  191. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  192. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  193. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  194. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  195. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  196. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  197. fontTools/ttLib/tables/S_V_G_.py +223 -0
  198. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  199. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  200. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  201. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  202. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  203. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  204. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  205. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  206. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  207. fontTools/ttLib/tables/T_S_I__0.py +70 -0
  208. fontTools/ttLib/tables/T_S_I__1.py +166 -0
  209. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  210. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  211. fontTools/ttLib/tables/T_S_I__5.py +60 -0
  212. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  213. fontTools/ttLib/tables/TupleVariation.py +884 -0
  214. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  215. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  216. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  217. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  218. fontTools/ttLib/tables/__init__.py +98 -0
  219. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  220. fontTools/ttLib/tables/_a_v_a_r.py +191 -0
  221. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  222. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  223. fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
  224. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  225. fontTools/ttLib/tables/_c_v_t.py +57 -0
  226. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  227. fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  228. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  229. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  230. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  231. fontTools/ttLib/tables/_g_l_y_f.py +2312 -0
  232. fontTools/ttLib/tables/_g_v_a_r.py +337 -0
  233. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  234. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  235. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  236. fontTools/ttLib/tables/_h_m_t_x.py +160 -0
  237. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  238. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  239. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  240. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  241. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  242. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  243. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  244. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  245. fontTools/ttLib/tables/_n_a_m_e.py +1237 -0
  246. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  247. fontTools/ttLib/tables/_p_o_s_t.py +320 -0
  248. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  249. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  250. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  251. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  252. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  253. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  254. fontTools/ttLib/tables/asciiTable.py +20 -0
  255. fontTools/ttLib/tables/grUtils.py +92 -0
  256. fontTools/ttLib/tables/otBase.py +1466 -0
  257. fontTools/ttLib/tables/otConverters.py +2068 -0
  258. fontTools/ttLib/tables/otData.py +6400 -0
  259. fontTools/ttLib/tables/otTables.py +2708 -0
  260. fontTools/ttLib/tables/otTraverse.py +163 -0
  261. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  262. fontTools/ttLib/tables/sbixStrike.py +177 -0
  263. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  264. fontTools/ttLib/tables/ttProgram.py +594 -0
  265. fontTools/ttLib/ttCollection.py +125 -0
  266. fontTools/ttLib/ttFont.py +1157 -0
  267. fontTools/ttLib/ttGlyphSet.py +490 -0
  268. fontTools/ttLib/ttVisitor.py +32 -0
  269. fontTools/ttLib/woff2.py +1683 -0
  270. fontTools/ttx.py +479 -0
  271. fontTools/ufoLib/__init__.py +2477 -0
  272. fontTools/ufoLib/converters.py +398 -0
  273. fontTools/ufoLib/errors.py +30 -0
  274. fontTools/ufoLib/etree.py +6 -0
  275. fontTools/ufoLib/filenames.py +346 -0
  276. fontTools/ufoLib/glifLib.py +2029 -0
  277. fontTools/ufoLib/kerning.py +121 -0
  278. fontTools/ufoLib/plistlib.py +47 -0
  279. fontTools/ufoLib/pointPen.py +6 -0
  280. fontTools/ufoLib/utils.py +79 -0
  281. fontTools/ufoLib/validators.py +1186 -0
  282. fontTools/unicode.py +50 -0
  283. fontTools/unicodedata/Blocks.py +801 -0
  284. fontTools/unicodedata/Mirrored.py +446 -0
  285. fontTools/unicodedata/OTTags.py +50 -0
  286. fontTools/unicodedata/ScriptExtensions.py +826 -0
  287. fontTools/unicodedata/Scripts.py +3617 -0
  288. fontTools/unicodedata/__init__.py +302 -0
  289. fontTools/varLib/__init__.py +1517 -0
  290. fontTools/varLib/__main__.py +6 -0
  291. fontTools/varLib/avar.py +260 -0
  292. fontTools/varLib/avarPlanner.py +1004 -0
  293. fontTools/varLib/builder.py +215 -0
  294. fontTools/varLib/cff.py +631 -0
  295. fontTools/varLib/errors.py +219 -0
  296. fontTools/varLib/featureVars.py +695 -0
  297. fontTools/varLib/hvar.py +113 -0
  298. fontTools/varLib/instancer/__init__.py +1946 -0
  299. fontTools/varLib/instancer/__main__.py +5 -0
  300. fontTools/varLib/instancer/featureVars.py +190 -0
  301. fontTools/varLib/instancer/names.py +388 -0
  302. fontTools/varLib/instancer/solver.py +309 -0
  303. fontTools/varLib/interpolatable.py +1209 -0
  304. fontTools/varLib/interpolatableHelpers.py +396 -0
  305. fontTools/varLib/interpolatablePlot.py +1269 -0
  306. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  307. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  308. fontTools/varLib/interpolate_layout.py +124 -0
  309. fontTools/varLib/iup.c +19830 -0
  310. fontTools/varLib/iup.cpython-313-aarch64-linux-gnu.so +0 -0
  311. fontTools/varLib/iup.py +490 -0
  312. fontTools/varLib/merger.py +1717 -0
  313. fontTools/varLib/models.py +642 -0
  314. fontTools/varLib/multiVarStore.py +253 -0
  315. fontTools/varLib/mutator.py +518 -0
  316. fontTools/varLib/mvar.py +40 -0
  317. fontTools/varLib/plot.py +238 -0
  318. fontTools/varLib/stat.py +149 -0
  319. fontTools/varLib/varStore.py +739 -0
  320. fontTools/voltLib/__init__.py +5 -0
  321. fontTools/voltLib/__main__.py +206 -0
  322. fontTools/voltLib/ast.py +452 -0
  323. fontTools/voltLib/error.py +12 -0
  324. fontTools/voltLib/lexer.py +99 -0
  325. fontTools/voltLib/parser.py +664 -0
  326. fontTools/voltLib/voltToFea.py +911 -0
  327. fonttools-4.58.3.data/data/share/man/man1/ttx.1 +225 -0
  328. fonttools-4.58.3.dist-info/METADATA +2133 -0
  329. fonttools-4.58.3.dist-info/RECORD +334 -0
  330. fonttools-4.58.3.dist-info/WHEEL +7 -0
  331. fonttools-4.58.3.dist-info/entry_points.txt +5 -0
  332. fonttools-4.58.3.dist-info/licenses/LICENSE +21 -0
  333. fonttools-4.58.3.dist-info/licenses/LICENSE.external +359 -0
  334. fonttools-4.58.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,203 @@
1
+ """CFF2 to CFF converter."""
2
+
3
+ from fontTools.ttLib import TTFont, newTable
4
+ from fontTools.misc.cliTools import makeOutputFileName
5
+ from fontTools.cffLib import (
6
+ TopDictIndex,
7
+ buildOrder,
8
+ buildDefaults,
9
+ topDictOperators,
10
+ privateDictOperators,
11
+ )
12
+ from .width import optimizeWidths
13
+ from collections import defaultdict
14
+ import logging
15
+
16
+
17
+ __all__ = ["convertCFF2ToCFF", "main"]
18
+
19
+
20
+ log = logging.getLogger("fontTools.cffLib")
21
+
22
+
23
+ def _convertCFF2ToCFF(cff, otFont):
24
+ """Converts this object from CFF2 format to CFF format. This conversion
25
+ is done 'in-place'. The conversion cannot be reversed.
26
+
27
+ The CFF2 font cannot be variable. (TODO Accept those and convert to the
28
+ default instance?)
29
+
30
+ This assumes a decompiled CFF table. (i.e. that the object has been
31
+ filled via :meth:`decompile` and e.g. not loaded from XML.)"""
32
+
33
+ cff.major = 1
34
+
35
+ topDictData = TopDictIndex(None)
36
+ for item in cff.topDictIndex:
37
+ # Iterate over, such that all are decompiled
38
+ item.cff2GetGlyphOrder = None
39
+ topDictData.append(item)
40
+ cff.topDictIndex = topDictData
41
+ topDict = topDictData[0]
42
+
43
+ if hasattr(topDict, "VarStore"):
44
+ raise ValueError("Variable CFF2 font cannot be converted to CFF format.")
45
+
46
+ opOrder = buildOrder(topDictOperators)
47
+ topDict.order = opOrder
48
+ for key in topDict.rawDict.keys():
49
+ if key not in opOrder:
50
+ del topDict.rawDict[key]
51
+ if hasattr(topDict, key):
52
+ delattr(topDict, key)
53
+
54
+ fdArray = topDict.FDArray
55
+ charStrings = topDict.CharStrings
56
+
57
+ defaults = buildDefaults(privateDictOperators)
58
+ order = buildOrder(privateDictOperators)
59
+ for fd in fdArray:
60
+ fd.setCFF2(False)
61
+ privateDict = fd.Private
62
+ privateDict.order = order
63
+ for key in order:
64
+ if key not in privateDict.rawDict and key in defaults:
65
+ privateDict.rawDict[key] = defaults[key]
66
+ for key in privateDict.rawDict.keys():
67
+ if key not in order:
68
+ del privateDict.rawDict[key]
69
+ if hasattr(privateDict, key):
70
+ delattr(privateDict, key)
71
+
72
+ for cs in charStrings.values():
73
+ cs.decompile()
74
+ cs.program.append("endchar")
75
+ for subrSets in [cff.GlobalSubrs] + [
76
+ getattr(fd.Private, "Subrs", []) for fd in fdArray
77
+ ]:
78
+ for cs in subrSets:
79
+ cs.program.append("return")
80
+
81
+ # Add (optimal) width to CharStrings that need it.
82
+ widths = defaultdict(list)
83
+ metrics = otFont["hmtx"].metrics
84
+ for glyphName in charStrings.keys():
85
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
86
+ if fdIndex == None:
87
+ fdIndex = 0
88
+ widths[fdIndex].append(metrics[glyphName][0])
89
+ for fdIndex, widthList in widths.items():
90
+ bestDefault, bestNominal = optimizeWidths(widthList)
91
+ private = fdArray[fdIndex].Private
92
+ private.defaultWidthX = bestDefault
93
+ private.nominalWidthX = bestNominal
94
+ for glyphName in charStrings.keys():
95
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
96
+ if fdIndex == None:
97
+ fdIndex = 0
98
+ private = fdArray[fdIndex].Private
99
+ width = metrics[glyphName][0]
100
+ if width != private.defaultWidthX:
101
+ cs.program.insert(0, width - private.nominalWidthX)
102
+
103
+ mapping = {
104
+ name: ("cid" + str(n) if n else ".notdef")
105
+ for n, name in enumerate(topDict.charset)
106
+ }
107
+ topDict.charset = [
108
+ "cid" + str(n) if n else ".notdef" for n in range(len(topDict.charset))
109
+ ]
110
+ charStrings.charStrings = {
111
+ mapping[name]: v for name, v in charStrings.charStrings.items()
112
+ }
113
+
114
+ # I'm not sure why the following is *not* necessary. And it breaks
115
+ # the output if I add it.
116
+ # topDict.ROS = ("Adobe", "Identity", 0)
117
+
118
+
119
+ def convertCFF2ToCFF(font, *, updatePostTable=True):
120
+ cff = font["CFF2"].cff
121
+ _convertCFF2ToCFF(cff, font)
122
+ del font["CFF2"]
123
+ table = font["CFF "] = newTable("CFF ")
124
+ table.cff = cff
125
+
126
+ if updatePostTable and "post" in font:
127
+ # Only version supported for fonts with CFF table is 0x00030000 not 0x20000
128
+ post = font["post"]
129
+ if post.formatType == 2.0:
130
+ post.formatType = 3.0
131
+
132
+
133
+ def main(args=None):
134
+ """Convert CFF OTF font to CFF2 OTF font"""
135
+ if args is None:
136
+ import sys
137
+
138
+ args = sys.argv[1:]
139
+
140
+ import argparse
141
+
142
+ parser = argparse.ArgumentParser(
143
+ "fonttools cffLib.CFFToCFF2",
144
+ description="Upgrade a CFF font to CFF2.",
145
+ )
146
+ parser.add_argument(
147
+ "input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
148
+ )
149
+ parser.add_argument(
150
+ "-o",
151
+ "--output",
152
+ metavar="OUTPUT.ttf",
153
+ default=None,
154
+ help="Output instance OTF file (default: INPUT-CFF2.ttf).",
155
+ )
156
+ parser.add_argument(
157
+ "--no-recalc-timestamp",
158
+ dest="recalc_timestamp",
159
+ action="store_false",
160
+ help="Don't set the output font's timestamp to the current time.",
161
+ )
162
+ loggingGroup = parser.add_mutually_exclusive_group(required=False)
163
+ loggingGroup.add_argument(
164
+ "-v", "--verbose", action="store_true", help="Run more verbosely."
165
+ )
166
+ loggingGroup.add_argument(
167
+ "-q", "--quiet", action="store_true", help="Turn verbosity off."
168
+ )
169
+ options = parser.parse_args(args)
170
+
171
+ from fontTools import configLogger
172
+
173
+ configLogger(
174
+ level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
175
+ )
176
+
177
+ import os
178
+
179
+ infile = options.input
180
+ if not os.path.isfile(infile):
181
+ parser.error("No such file '{}'".format(infile))
182
+
183
+ outfile = (
184
+ makeOutputFileName(infile, overWrite=True, suffix="-CFF")
185
+ if not options.output
186
+ else options.output
187
+ )
188
+
189
+ font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
190
+
191
+ convertCFF2ToCFF(font)
192
+
193
+ log.info(
194
+ "Saving %s",
195
+ outfile,
196
+ )
197
+ font.save(outfile)
198
+
199
+
200
+ if __name__ == "__main__":
201
+ import sys
202
+
203
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,305 @@
1
+ """CFF to CFF2 converter."""
2
+
3
+ from fontTools.ttLib import TTFont, newTable
4
+ from fontTools.misc.cliTools import makeOutputFileName
5
+ from fontTools.misc.psCharStrings import T2WidthExtractor
6
+ from fontTools.cffLib import (
7
+ TopDictIndex,
8
+ FDArrayIndex,
9
+ FontDict,
10
+ buildOrder,
11
+ topDictOperators,
12
+ privateDictOperators,
13
+ topDictOperators2,
14
+ privateDictOperators2,
15
+ )
16
+ from io import BytesIO
17
+ import logging
18
+
19
+ __all__ = ["convertCFFToCFF2", "main"]
20
+
21
+
22
+ log = logging.getLogger("fontTools.cffLib")
23
+
24
+
25
+ class _NominalWidthUsedError(Exception):
26
+ def __add__(self, other):
27
+ raise self
28
+
29
+ def __radd__(self, other):
30
+ raise self
31
+
32
+
33
+ def _convertCFFToCFF2(cff, otFont):
34
+ """Converts this object from CFF format to CFF2 format. This conversion
35
+ is done 'in-place'. The conversion cannot be reversed.
36
+
37
+ This assumes a decompiled CFF table. (i.e. that the object has been
38
+ filled via :meth:`decompile` and e.g. not loaded from XML.)"""
39
+
40
+ # Clean up T2CharStrings
41
+
42
+ topDict = cff.topDictIndex[0]
43
+ fdArray = topDict.FDArray if hasattr(topDict, "FDArray") else None
44
+ charStrings = topDict.CharStrings
45
+ globalSubrs = cff.GlobalSubrs
46
+ localSubrs = (
47
+ [getattr(fd.Private, "Subrs", []) for fd in fdArray]
48
+ if fdArray
49
+ else (
50
+ [topDict.Private.Subrs]
51
+ if hasattr(topDict, "Private") and hasattr(topDict.Private, "Subrs")
52
+ else []
53
+ )
54
+ )
55
+
56
+ for glyphName in charStrings.keys():
57
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
58
+ cs.decompile()
59
+
60
+ # Clean up subroutines first
61
+ for subrs in [globalSubrs] + localSubrs:
62
+ for subr in subrs:
63
+ program = subr.program
64
+ i = j = len(program)
65
+ try:
66
+ i = program.index("return")
67
+ except ValueError:
68
+ pass
69
+ try:
70
+ j = program.index("endchar")
71
+ except ValueError:
72
+ pass
73
+ program[min(i, j) :] = []
74
+
75
+ # Clean up glyph charstrings
76
+ removeUnusedSubrs = False
77
+ nominalWidthXError = _NominalWidthUsedError()
78
+ for glyphName in charStrings.keys():
79
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
80
+ program = cs.program
81
+
82
+ thisLocalSubrs = (
83
+ localSubrs[fdIndex]
84
+ if fdIndex is not None
85
+ else (
86
+ getattr(topDict.Private, "Subrs", [])
87
+ if hasattr(topDict, "Private")
88
+ else []
89
+ )
90
+ )
91
+
92
+ # Intentionally use custom type for nominalWidthX, such that any
93
+ # CharString that has an explicit width encoded will throw back to us.
94
+ extractor = T2WidthExtractor(
95
+ thisLocalSubrs,
96
+ globalSubrs,
97
+ nominalWidthXError,
98
+ 0,
99
+ )
100
+ try:
101
+ extractor.execute(cs)
102
+ except _NominalWidthUsedError:
103
+ # Program has explicit width. We want to drop it, but can't
104
+ # just pop the first number since it may be a subroutine call.
105
+ # Instead, when seeing that, we embed the subroutine and recurse.
106
+ # If this ever happened, we later prune unused subroutines.
107
+ while len(program) >= 2 and program[1] in ["callsubr", "callgsubr"]:
108
+ removeUnusedSubrs = True
109
+ subrNumber = program.pop(0)
110
+ assert isinstance(subrNumber, int), subrNumber
111
+ op = program.pop(0)
112
+ bias = extractor.localBias if op == "callsubr" else extractor.globalBias
113
+ subrNumber += bias
114
+ subrSet = thisLocalSubrs if op == "callsubr" else globalSubrs
115
+ subrProgram = subrSet[subrNumber].program
116
+ program[:0] = subrProgram
117
+ # Now pop the actual width
118
+ assert len(program) >= 1, program
119
+ program.pop(0)
120
+
121
+ if program and program[-1] == "endchar":
122
+ program.pop()
123
+
124
+ if removeUnusedSubrs:
125
+ cff.remove_unused_subroutines()
126
+
127
+ # Upconvert TopDict
128
+
129
+ cff.major = 2
130
+ cff2GetGlyphOrder = cff.otFont.getGlyphOrder
131
+ topDictData = TopDictIndex(None, cff2GetGlyphOrder)
132
+ for item in cff.topDictIndex:
133
+ # Iterate over, such that all are decompiled
134
+ topDictData.append(item)
135
+ cff.topDictIndex = topDictData
136
+ topDict = topDictData[0]
137
+ if hasattr(topDict, "Private"):
138
+ privateDict = topDict.Private
139
+ else:
140
+ privateDict = None
141
+ opOrder = buildOrder(topDictOperators2)
142
+ topDict.order = opOrder
143
+ topDict.cff2GetGlyphOrder = cff2GetGlyphOrder
144
+
145
+ if not hasattr(topDict, "FDArray"):
146
+ fdArray = topDict.FDArray = FDArrayIndex()
147
+ fdArray.strings = None
148
+ fdArray.GlobalSubrs = topDict.GlobalSubrs
149
+ topDict.GlobalSubrs.fdArray = fdArray
150
+ charStrings = topDict.CharStrings
151
+ if charStrings.charStringsAreIndexed:
152
+ charStrings.charStringsIndex.fdArray = fdArray
153
+ else:
154
+ charStrings.fdArray = fdArray
155
+ fontDict = FontDict()
156
+ fontDict.setCFF2(True)
157
+ fdArray.append(fontDict)
158
+ fontDict.Private = privateDict
159
+ privateOpOrder = buildOrder(privateDictOperators2)
160
+ if privateDict is not None:
161
+ for entry in privateDictOperators:
162
+ key = entry[1]
163
+ if key not in privateOpOrder:
164
+ if key in privateDict.rawDict:
165
+ # print "Removing private dict", key
166
+ del privateDict.rawDict[key]
167
+ if hasattr(privateDict, key):
168
+ delattr(privateDict, key)
169
+ # print "Removing privateDict attr", key
170
+ else:
171
+ # clean up the PrivateDicts in the fdArray
172
+ fdArray = topDict.FDArray
173
+ privateOpOrder = buildOrder(privateDictOperators2)
174
+ for fontDict in fdArray:
175
+ fontDict.setCFF2(True)
176
+ for key in list(fontDict.rawDict.keys()):
177
+ if key not in fontDict.order:
178
+ del fontDict.rawDict[key]
179
+ if hasattr(fontDict, key):
180
+ delattr(fontDict, key)
181
+
182
+ privateDict = fontDict.Private
183
+ for entry in privateDictOperators:
184
+ key = entry[1]
185
+ if key not in privateOpOrder:
186
+ if key in list(privateDict.rawDict.keys()):
187
+ # print "Removing private dict", key
188
+ del privateDict.rawDict[key]
189
+ if hasattr(privateDict, key):
190
+ delattr(privateDict, key)
191
+ # print "Removing privateDict attr", key
192
+
193
+ # Now delete up the deprecated topDict operators from CFF 1.0
194
+ for entry in topDictOperators:
195
+ key = entry[1]
196
+ # We seem to need to keep the charset operator for now,
197
+ # or we fail to compile with some fonts, like AdditionFont.otf.
198
+ # I don't know which kind of CFF font those are. But keeping
199
+ # charset seems to work. It will be removed when we save and
200
+ # read the font again.
201
+ #
202
+ # AdditionFont.otf has <Encoding name="StandardEncoding"/>.
203
+ if key == "charset":
204
+ continue
205
+ if key not in opOrder:
206
+ if key in topDict.rawDict:
207
+ del topDict.rawDict[key]
208
+ if hasattr(topDict, key):
209
+ delattr(topDict, key)
210
+
211
+ # TODO(behdad): What does the following comment even mean? Both CFF and CFF2
212
+ # use the same T2Charstring class. I *think* what it means is that the CharStrings
213
+ # were loaded for CFF1, and we need to reload them for CFF2 to set varstore, etc
214
+ # on them. At least that's what I understand. It's probably safe to remove this
215
+ # and just set vstore where needed.
216
+ #
217
+ # See comment above about charset as well.
218
+
219
+ # At this point, the Subrs and Charstrings are all still T2Charstring class
220
+ # easiest to fix this by compiling, then decompiling again
221
+ file = BytesIO()
222
+ cff.compile(file, otFont, isCFF2=True)
223
+ file.seek(0)
224
+ cff.decompile(file, otFont, isCFF2=True)
225
+
226
+
227
+ def convertCFFToCFF2(font):
228
+ cff = font["CFF "].cff
229
+ del font["CFF "]
230
+ _convertCFFToCFF2(cff, font)
231
+ table = font["CFF2"] = newTable("CFF2")
232
+ table.cff = cff
233
+
234
+
235
+ def main(args=None):
236
+ """Convert CFF OTF font to CFF2 OTF font"""
237
+ if args is None:
238
+ import sys
239
+
240
+ args = sys.argv[1:]
241
+
242
+ import argparse
243
+
244
+ parser = argparse.ArgumentParser(
245
+ "fonttools cffLib.CFFToCFF2",
246
+ description="Upgrade a CFF font to CFF2.",
247
+ )
248
+ parser.add_argument(
249
+ "input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
250
+ )
251
+ parser.add_argument(
252
+ "-o",
253
+ "--output",
254
+ metavar="OUTPUT.ttf",
255
+ default=None,
256
+ help="Output instance OTF file (default: INPUT-CFF2.ttf).",
257
+ )
258
+ parser.add_argument(
259
+ "--no-recalc-timestamp",
260
+ dest="recalc_timestamp",
261
+ action="store_false",
262
+ help="Don't set the output font's timestamp to the current time.",
263
+ )
264
+ loggingGroup = parser.add_mutually_exclusive_group(required=False)
265
+ loggingGroup.add_argument(
266
+ "-v", "--verbose", action="store_true", help="Run more verbosely."
267
+ )
268
+ loggingGroup.add_argument(
269
+ "-q", "--quiet", action="store_true", help="Turn verbosity off."
270
+ )
271
+ options = parser.parse_args(args)
272
+
273
+ from fontTools import configLogger
274
+
275
+ configLogger(
276
+ level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
277
+ )
278
+
279
+ import os
280
+
281
+ infile = options.input
282
+ if not os.path.isfile(infile):
283
+ parser.error("No such file '{}'".format(infile))
284
+
285
+ outfile = (
286
+ makeOutputFileName(infile, overWrite=True, suffix="-CFF2")
287
+ if not options.output
288
+ else options.output
289
+ )
290
+
291
+ font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
292
+
293
+ convertCFFToCFF2(font)
294
+
295
+ log.info(
296
+ "Saving %s",
297
+ outfile,
298
+ )
299
+ font.save(outfile)
300
+
301
+
302
+ if __name__ == "__main__":
303
+ import sys
304
+
305
+ sys.exit(main(sys.argv[1:]))