|
1 #!/usr/bin/python |
|
2 # vim: set shiftwidth=4 tabstop=8 autoindent expandtab: |
|
3 # This Source Code Form is subject to the terms of the Mozilla Public |
|
4 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
6 |
|
7 # For general fontforge documentation, see: |
|
8 # http://fontforge.sourceforge.net/ |
|
9 # For fontforge scripting documentation, see: |
|
10 # http://fontforge.sourceforge.net/scripting-tutorial.html |
|
11 # http://fontforge.sourceforge.net/scripting.html |
|
12 # and most importantly: |
|
13 # http://fontforge.sourceforge.net/python.html |
|
14 |
|
15 # To install what you need, on Ubuntu, |
|
16 # sudo apt-get install python-fontforge |
|
17 |
|
18 from __future__ import print_function |
|
19 import fontforge |
|
20 |
|
21 em = 1000 |
|
22 |
|
23 def newMathFont(aName): |
|
24 print("Generating %s.otf..." % aName, end="") |
|
25 mathFont = fontforge.font() |
|
26 mathFont.fontname = aName |
|
27 mathFont.familyname = aName |
|
28 mathFont.fullname = aName |
|
29 mathFont.copyright = "Copyright (c) 2014 Mozilla Corporation" |
|
30 mathFont.encoding = "UnicodeFull" |
|
31 |
|
32 # Create a space character. Also force the creation of some MATH subtables |
|
33 # so that OTS will not reject the MATH table. |
|
34 g = mathFont.createChar(ord(" "), "space") |
|
35 g.width = em |
|
36 g.italicCorrection = 0 |
|
37 g.topaccent = 0 |
|
38 g.mathKern.bottomLeft = tuple([(0,0)]) |
|
39 g.mathKern.bottomRight = tuple([(0,0)]) |
|
40 g.mathKern.topLeft = tuple([(0,0)]) |
|
41 g.mathKern.topRight = tuple([(0,0)]) |
|
42 mathFont[ord(" ")].horizontalVariants = "space" |
|
43 mathFont[ord(" ")].verticalVariants = "space" |
|
44 return mathFont |
|
45 |
|
46 def saveMathFont(aFont): |
|
47 aFont.em = em |
|
48 aFont.ascent = aFont.descent = em/2 |
|
49 aFont.hhea_ascent = aFont.os2_typoascent = aFont.os2_winascent = em/2 |
|
50 aFont.descent = aFont.hhea_descent = em/2 |
|
51 aFont.os2_typodescent = aFont.os2_windescent = em/2 |
|
52 aFont.hhea_ascent_add = aFont.hhea_descent_add = 0 |
|
53 aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0 |
|
54 aFont.os2_winascent_add = aFont.os2_windescent_add = 0 |
|
55 aFont.os2_use_typo_metrics = True |
|
56 aFont.generate(aFont.fontname + ".otf") |
|
57 print(" done.") |
|
58 |
|
59 ################################################################################ |
|
60 # Glyph variants and constructions |
|
61 f = newMathFont("stretchy") |
|
62 nvariants = 3 |
|
63 |
|
64 # Draw boxes for the size variants and glues |
|
65 for i in range(0, nvariants): |
|
66 s = em * (i + 1) |
|
67 |
|
68 g = f.createChar(-1, "h%d" % i) |
|
69 p = g.glyphPen() |
|
70 p.moveTo(0, -em) |
|
71 p.lineTo(0, em) |
|
72 p.lineTo(s, em) |
|
73 p.lineTo(s, -em) |
|
74 p.closePath() |
|
75 g.width = s |
|
76 |
|
77 g = f.createChar(-1, "v%d" % i) |
|
78 p = g.glyphPen() |
|
79 p.moveTo(0, 0) |
|
80 p.lineTo(0, s) |
|
81 p.lineTo(2 * em, s) |
|
82 p.lineTo(2 * em, 0) |
|
83 p.closePath(); |
|
84 g.width = 2 * em |
|
85 |
|
86 # Draw some pieces for stretchy operators |
|
87 s = em * nvariants |
|
88 |
|
89 g = f.createChar(-1, "left") |
|
90 p = g.glyphPen() |
|
91 p.moveTo(0, -2 * em) |
|
92 p.lineTo(0, 2 * em) |
|
93 p.lineTo(s, em) |
|
94 p.lineTo(s, -em) |
|
95 p.closePath(); |
|
96 g.width = s |
|
97 |
|
98 g = f.createChar(-1, "right") |
|
99 p = g.glyphPen() |
|
100 p.moveTo(0, -em) |
|
101 p.lineTo(0, em) |
|
102 p.lineTo(s, 2 * em) |
|
103 p.lineTo(s, -2 * em) |
|
104 p.closePath(); |
|
105 g.width = s |
|
106 |
|
107 g = f.createChar(-1, "hmid") |
|
108 p = g.glyphPen() |
|
109 p.moveTo(0, -em) |
|
110 p.lineTo(0, em) |
|
111 p.lineTo(s, 2 * em) |
|
112 p.lineTo(2 * s, em) |
|
113 p.lineTo(2 * s, -em) |
|
114 p.lineTo(s, -2 * em) |
|
115 p.closePath(); |
|
116 g.width = 2 * s |
|
117 |
|
118 g = f.createChar(-1, "bottom") |
|
119 p = g.glyphPen() |
|
120 p.moveTo(0, 0) |
|
121 p.lineTo(0, s) |
|
122 p.lineTo(2 * em, s) |
|
123 p.lineTo(4 * em, 0) |
|
124 p.closePath(); |
|
125 g.width = 4 * em |
|
126 |
|
127 g = f.createChar(-1, "top") |
|
128 p = g.glyphPen() |
|
129 p.moveTo(0, 0) |
|
130 p.lineTo(4 * em, 0) |
|
131 p.lineTo(2 * em, -s) |
|
132 p.lineTo(0, -s) |
|
133 p.closePath(); |
|
134 g.width = 4 * em |
|
135 |
|
136 g = f.createChar(-1, "vmid") |
|
137 p = g.glyphPen() |
|
138 p.moveTo(0, s) |
|
139 p.lineTo(2 * em, s) |
|
140 p.lineTo(4 * em, 0) |
|
141 p.lineTo(2 * em, -s) |
|
142 p.lineTo(0, -s) |
|
143 p.closePath(); |
|
144 g.width = 3 * em |
|
145 |
|
146 # Create small rectangle of various size for some exotic arrows that are |
|
147 # unlikely to be stretchable with standard fonts. |
|
148 hstretchy = [ |
|
149 0x219C, # leftwards wave arrow |
|
150 0x219D, # rightwards wave arrow |
|
151 0x219E, # leftwards two headed arrow |
|
152 0x21A0, # rightwards two headed arrow |
|
153 0x21A2 # leftwards arrow with tail |
|
154 ] |
|
155 vstretchy = [ |
|
156 0x219F, # upwards two headed arrow |
|
157 0x21A1, # downwards two headed arrow |
|
158 0x21A5, # upwards arrow from bar |
|
159 0x21A7, # downwards arrow from bar |
|
160 0x21A8 # up down arrow with base |
|
161 ] |
|
162 for i in range(0, 1 + nvariants + 1): |
|
163 s = (i + 1) * em/10 |
|
164 |
|
165 g = f.createChar(hstretchy[i]) |
|
166 p = g.glyphPen() |
|
167 p.moveTo(0, -em/10) |
|
168 p.lineTo(0, em/10) |
|
169 p.lineTo(s, em/10) |
|
170 p.lineTo(s, -em/10) |
|
171 p.closePath() |
|
172 g.width = s |
|
173 |
|
174 g = f.createChar(vstretchy[i]) |
|
175 p = g.glyphPen() |
|
176 p.moveTo(0, 0) |
|
177 p.lineTo(0, s) |
|
178 p.lineTo(2 * em/10, s) |
|
179 p.lineTo(2 * em/10, 0) |
|
180 p.closePath(); |
|
181 g.width = 2 * em/10 |
|
182 |
|
183 # hstretchy[0] and vstretchy[0] have all the variants and the components. The others only have one of them. |
|
184 s = em * nvariants |
|
185 |
|
186 f[hstretchy[0]].horizontalVariants = "uni219C h0 h1 h2" |
|
187 f[hstretchy[0]].horizontalComponents = (("left", False, 0, 0, s), \ |
|
188 ("h2", True, 0, 0, s), ("hmid", False, 0, 0, 2 * s), ("h2", True, 0, 0, s), \ |
|
189 ("right", False, 0, 0, s)) |
|
190 |
|
191 f[hstretchy[1]].horizontalVariants = "uni219D h0" |
|
192 f[hstretchy[2]].horizontalVariants = "uni219E h1" |
|
193 f[hstretchy[3]].horizontalVariants = "uni21A0 h2" |
|
194 f[hstretchy[4]].horizontalVariants = "uni21A2 h2" |
|
195 f[hstretchy[4]].horizontalComponents = f[hstretchy[0]].horizontalComponents |
|
196 |
|
197 f[vstretchy[0]].verticalVariants = "uni219F v0 v1 v2" |
|
198 f[vstretchy[0]].verticalComponents = (("bottom", False, 0, 0, s), \ |
|
199 ("v2", True, 0, 0, s), ("vmid", False, 0, 0, 2 * s), ("v2", True, 0, 0, s), \ |
|
200 ("top", False, 0, 0, s)) |
|
201 |
|
202 f[vstretchy[1]].verticalVariants = "uni21A1 v0" |
|
203 f[vstretchy[2]].verticalVariants = "uni21A5 v1" |
|
204 f[vstretchy[3]].verticalVariants = "uni21A7 v2" |
|
205 f[vstretchy[4]].verticalVariants = "uni21A8" |
|
206 f[vstretchy[4]].verticalComponents = f[vstretchy[0]].verticalComponents |
|
207 |
|
208 ################################################################################ |
|
209 # Testing DisplayOperatorMinHeight |
|
210 f.math.DisplayOperatorMinHeight = 8 * em |
|
211 largeop = [0x2A1B, 0x2A1C] # integral with overbar/underbar |
|
212 |
|
213 # Draw boxes of size 1, 2, 7, 8, 9em. |
|
214 for i in [1, 2, 7, 8, 9]: |
|
215 s = em * i |
|
216 if i == 1 or i == 2: |
|
217 g = f.createChar(largeop[i-1]) |
|
218 else: |
|
219 g = f.createChar(-1, "L%d" % i) |
|
220 p = g.glyphPen() |
|
221 p.moveTo(0, 0) |
|
222 p.lineTo(0, s) |
|
223 p.lineTo(s, s) |
|
224 p.lineTo(s, 0) |
|
225 p.closePath(); |
|
226 g.width = s |
|
227 |
|
228 f[largeop[0]].verticalVariants = "uni2A1B L7 L8 L9" |
|
229 f[largeop[1]].verticalVariants = "uni2A1C L8" |
|
230 |
|
231 saveMathFont(f) |