math-map.lua /size: 30 Kb    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['math-map'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to math-ini.mkiv",
5    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10-- persian: we will also provide mappers for other scripts
11-- todo   : alphabets namespace
12-- maybe  : script/scriptscript dynamic,
13-- check  : (U+2202,U+1D715) : upright
14--          (U+2202,U+1D715) : italic
15--          (U+2202,U+1D715) : upright
16--          add them to the regular vectors below so that they honor \it etc
17
18local type, next = type, next
19local merged, sortedhash = table.merged, table.sortedhash
20local extract = bit32.extract
21
22local allocate            = utilities.storage.allocate
23
24local otffeatures         = fonts.constructors.features.otf
25local registerotffeature  = otffeatures.register
26
27local setmetatableindex   = table.setmetatableindex
28
29local texgetattribute     = tex.getattribute
30local texsetattribute     = tex.setattribute
31
32local trace_greek         = false  trackers.register("math.greek",  function(v) trace_greek = v end)
33local report_remapping    = logs.reporter("mathematics","remapping")
34
35mathematics               = mathematics or { }
36local mathematics         = mathematics
37
38local implement           = interfaces.implement
39
40-- Unfortunately some alphabets have gaps (thereby troubling all applications that
41-- need to deal with math). Somewhat strange considering all those weird symbols that
42-- were added afterwards. The following trickery (and data) is only to be used for
43-- diagnostics and quick and dirty alphabet tracing (s-mat-10.mkiv) as we deal with
44-- it otherwise.
45
46-- todo: allocate
47
48mathematics.styles       = allocate { "regular", "sansserif", "monospaced", "fraktur", "script", "blackboard" }
49mathematics.alternatives = allocate { "normal", "bold", "italic", "bolditalic" }
50mathematics.sets         = allocate { "ucletters", "lcletters", "digits", "ucgreek", "lcgreek", "symbols" }
51
52mathematics.charactersets = allocate {
53    ucletters = {
54        0x00041, 0x00042, 0x00043, 0x00044, 0x00045,
55        0x00046, 0x00047, 0x00048, 0x00049, 0x0004A,
56        0x0004B, 0x0004C, 0x0004D, 0x0004E, 0x0004F,
57        0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
58        0x00055, 0x00056, 0x00057, 0x00058, 0x00059,
59        0x0005A,
60    },
61    lcletters = {
62        0x00061, 0x00062, 0x00063, 0x00064, 0x00065,
63        0x00066, 0x00067, 0x00068, 0x00069, 0x0006A,
64        0x0006B, 0x0006C, 0x0006D, 0x0006E, 0x0006F,
65        0x00070, 0x00071, 0x00072, 0x00073, 0x00074,
66        0x00075, 0x00076, 0x00077, 0x00078, 0x00079,
67        0x0007A,
68    },
69    digits = {
70        0x00030, 0x00031, 0x00032, 0x00033, 0x00034,
71        0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
72    },
73    ucgreek = {
74        0x0391, 0x0392, 0x0393, 0x0394, 0x0395,
75        0x0396, 0x0397, 0x0398, 0x0399, 0x039A,
76        0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
77        0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5,
78        0x03A6, 0x03A7, 0x03A8, 0x03A9
79    },
80    lcgreek = {
81        0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5,
82        0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA,
83        0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
84        0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4,
85        0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9,
86        0x03D1, 0x03D5, 0x03D6, 0x03F0, 0x03F1,
87        0x03F4, 0x03F5
88    },
89}
90
91mathematics.gaps = allocate {
92    [0x1D455] = 0x0210E, -- ℎ h
93    [0x1D49D] = 0x0212C, -- ℬ script B
94    [0x1D4A0] = 0x02130, -- ℰ script E
95    [0x1D4A1] = 0x02131, -- ℱ script F
96    [0x1D4A3] = 0x0210B, -- ℋ script H
97    [0x1D4A4] = 0x02110, -- ℐ script I
98    [0x1D4A7] = 0x02112, -- ℒ script L
99    [0x1D4A8] = 0x02133, -- ℳ script M
100    [0x1D4AD] = 0x0211B, -- ℛ script R
101    [0x1D4BA] = 0x0212F, -- ℯ script e
102    [0x1D4BC] = 0x0210A, -- ℊ script g
103 -- [0x1D4C1] = 0x02113, -- exception: liter
104    [0x1D4C4] = 0x02134, -- ℴ script o
105    [0x1D506] = 0x0212D, -- ℭ fraktur C
106    [0x1D50B] = 0x0210C, -- ℌ fraktur H
107    [0x1D50C] = 0x02111, -- ℑ fraktur I
108    [0x1D515] = 0x0211C, -- ℜ fraktur R
109    [0x1D51D] = 0x02128, -- ℨ fraktur Z
110    [0x1D53A] = 0x02102, -- ℂ bb C
111    [0x1D53F] = 0x0210D, -- ℍ bb H
112    [0x1D545] = 0x02115, -- ℕ bb N
113    [0x1D547] = 0x02119, -- ℙ bb P
114    [0x1D548] = 0x0211A, -- ℚ bb Q
115    [0x1D549] = 0x0211D, -- ℝ bb R
116    [0x1D551] = 0x02124, -- ℤ bb Z
117}
118
119local function fillinmathgaps(tfmdata,key,value)
120    local mathgaps     = mathematics.gaps
121    local characters   = tfmdata.characters
122    local descriptions = tfmdata.descriptions
123    for gap, original in next, mathgaps do
124        if characters[original] and not characters[gap] then
125            characters  [gap] = characters  [original]
126            descriptions[gap] = descriptions[original]
127        end
128    end
129end
130
131registerotffeature {
132    name         = "mathgaps",
133    description  = "plug gaps in math alphabets",
134    comment      = "regular document sources should not depend on this",
135    manipulators = {
136        base = fillinmathgaps,
137        node = fillinmathgaps,
138    }
139}
140
141-- we could use one level less and have tf etc be tables directly but the
142-- following approach permits easier remapping of a-a, A-Z and 0-9 to
143-- fallbacks; symbols is currently mostly greek
144
145local function todigit (n) local t = { } for i=0, 9 do t[0x00030+i] = n+i end return t end
146local function toupper (n) local t = { } for i=0,25 do t[0x00041+i] = n+i end return t end
147local function tolower (n) local t = { } for i=0,25 do t[0x00061+i] = n+i end return t end
148local function tovector(t)                                                    return t end
149
150-- how about 0x2A (ast)    cq. 0x2217
151--           0x2D (hyphen) cq. 0x2212
152--           0x3A (colon)  cq. 0x2236
153
154local regular_tf = {
155    digits    = todigit(0x00030),
156    ucletters = toupper(0x00041),
157    lcletters = tolower(0x00061),
158    ucgreek   = {
159        [0x0391]=0x0391, [0x0392]=0x0392, [0x0393]=0x0393, [0x0394]=0x0394, [0x0395]=0x0395,
160        [0x0396]=0x0396, [0x0397]=0x0397, [0x0398]=0x0398, [0x0399]=0x0399, [0x039A]=0x039A,
161        [0x039B]=0x039B, [0x039C]=0x039C, [0x039D]=0x039D, [0x039E]=0x039E, [0x039F]=0x039F,
162        [0x03A0]=0x03A0, [0x03A1]=0x03A1, [0x03A3]=0x03A3, [0x03A4]=0x03A4, [0x03A5]=0x03A5,
163        [0x03A6]=0x03A6, [0x03A7]=0x03A7, [0x03A8]=0x03A8, [0x03A9]=0x03A9,
164        },
165    lcgreek   = {
166        [0x03B1]=0x03B1, [0x03B2]=0x03B2, [0x03B3]=0x03B3, [0x03B4]=0x03B4, [0x03B5]=0x03B5,
167        [0x03B6]=0x03B6, [0x03B7]=0x03B7, [0x03B8]=0x03B8, [0x03B9]=0x03B9, [0x03BA]=0x03BA,
168        [0x03BB]=0x03BB, [0x03BC]=0x03BC, [0x03BD]=0x03BD, [0x03BE]=0x03BE, [0x03BF]=0x03BF,
169        [0x03C0]=0x03C0, [0x03C1]=0x03C1, [0x03C2]=0x03C2, [0x03C3]=0x03C3, [0x03C4]=0x03C4,
170        [0x03C5]=0x03C5, [0x03C6]=0x03C6, [0x03C7]=0x03C7, [0x03C8]=0x03C8, [0x03C9]=0x03C9,
171        [0x03D1]=0x03D1, [0x03D5]=0x03D5, [0x03D6]=0x03D6, [0x03F0]=0x03F0, [0x03F1]=0x03F1,
172        [0x03F4]=0x03F4, [0x03F5]=0x03F5,
173    },
174    symbols   = {
175        [0x2202]=0x2202, [0x2207]=0x2207,
176        [0x0027]=0x2032,  -- prime
177    },
178}
179
180local regular_it = {
181    digits    = tovector(regular_tf.digits),
182    ucletters = toupper(0x1D434),
183    lcletters = { -- H
184        [0x00061]=0x1D44E, [0x00062]=0x1D44F, [0x00063]=0x1D450, [0x00064]=0x1D451, [0x00065]=0x1D452,
185        [0x00066]=0x1D453, [0x00067]=0x1D454, [0x00068]=0x0210E, [0x00069]=0x1D456, [0x0006A]=0x1D457,
186        [0x0006B]=0x1D458, [0x0006C]=0x1D459, [0x0006D]=0x1D45A, [0x0006E]=0x1D45B, [0x0006F]=0x1D45C,
187        [0x00070]=0x1D45D, [0x00071]=0x1D45E, [0x00072]=0x1D45F, [0x00073]=0x1D460, [0x00074]=0x1D461,
188        [0x00075]=0x1D462, [0x00076]=0x1D463, [0x00077]=0x1D464, [0x00078]=0x1D465, [0x00079]=0x1D466,
189        [0x0007A]=0x1D467,
190        -- arabic
191        [0x00627] = 0x1EE00, [0x00628] = 0x1EE21, [0x0062A] = 0x1EE15, [0x0062B] = 0x1EE16,
192        [0x0062C] = 0x1EE22, [0x0062D] = 0x1EE07, [0x0062E] = 0x1EE17, [0x0062F] = 0x1EE03,
193        [0x00630] = 0x1EE18, [0x00631] = 0x1EE13, [0x00632] = 0x1EE06, [0x00633] = 0x1EE0E,
194        [0x00634] = 0x1EE14, [0x00635] = 0x1EE11, [0x00636] = 0x1EE19, [0x00637] = 0x1EE08,
195        [0x00638] = 0x1EE1A, [0x00639] = 0x1EE0F, [0x0063A] = 0x1EE1B, [0x00641] = 0x1EE10,
196        [0x00642] = 0x1EE12, [0x00643] = 0x1EE0A, [0x00644] = 0x1EE0B, [0x00645] = 0x1EE0C,
197        [0x00646] = 0x1EE0D, [0x00647] = 0x1EE24, [0x00648] = 0x1EE05, [0x0064A] = 0x1EE09,
198        [0x0066E] = 0x1EE1C, [0x0066F] = 0x1EE1F, [0x006A1] = 0x1EE1E, [0x006BA] = 0x1EE1D,
199    },
200    ucgreek   = {
201        [0x0391]=0x1D6E2, [0x0392]=0x1D6E3, [0x0393]=0x1D6E4, [0x0394]=0x1D6E5, [0x0395]=0x1D6E6,
202        [0x0396]=0x1D6E7, [0x0397]=0x1D6E8, [0x0398]=0x1D6E9, [0x0399]=0x1D6EA, [0x039A]=0x1D6EB,
203        [0x039B]=0x1D6EC, [0x039C]=0x1D6ED, [0x039D]=0x1D6EE, [0x039E]=0x1D6EF, [0x039F]=0x1D6F0,
204        [0x03A0]=0x1D6F1, [0x03A1]=0x1D6F2, [0x03A3]=0x1D6F4, [0x03A4]=0x1D6F5, [0x03A5]=0x1D6F6,
205        [0x03A6]=0x1D6F7, [0x03A7]=0x1D6F8, [0x03A8]=0x1D6F9, [0x03A9]=0x1D6FA,
206        },
207    lcgreek   = {
208        [0x03B1]=0x1D6FC, [0x03B2]=0x1D6FD, [0x03B3]=0x1D6FE, [0x03B4]=0x1D6FF, [0x03B5]=0x1D700,
209        [0x03B6]=0x1D701, [0x03B7]=0x1D702, [0x03B8]=0x1D703, [0x03B9]=0x1D704, [0x03BA]=0x1D705,
210        [0x03BB]=0x1D706, [0x03BC]=0x1D707, [0x03BD]=0x1D708, [0x03BE]=0x1D709, [0x03BF]=0x1D70A,
211        [0x03C0]=0x1D70B, [0x03C1]=0x1D70C, [0x03C2]=0x1D70D, [0x03C3]=0x1D70E, [0x03C4]=0x1D70F,
212        [0x03C5]=0x1D710, [0x03C6]=0x1D711, [0x03C7]=0x1D712, [0x03C8]=0x1D713, [0x03C9]=0x1D714,
213        [0x03D1]=0x1D717, [0x03D5]=0x1D719, [0x03D6]=0x1D71B, [0x03F0]=0x1D718, [0x03F1]=0x1D71A,
214        [0x03F4]=0x1D6F3, [0x03F5]=0x1D716,
215    },
216    symbols   = {
217        [0x2202]=0x1D715, [0x2207]=0x1D6FB,
218        [0x0027]=0x2032, -- prime
219    },
220}
221
222local regular_bf= {
223    digits    = todigit(0x1D7CE),
224    ucletters = toupper(0x1D400),
225    lcletters = tolower(0x1D41A),
226    ucgreek   = {
227        [0x0391]=0x1D6A8, [0x0392]=0x1D6A9, [0x0393]=0x1D6AA, [0x0394]=0x1D6AB, [0x0395]=0x1D6AC,
228        [0x0396]=0x1D6AD, [0x0397]=0x1D6AE, [0x0398]=0x1D6AF, [0x0399]=0x1D6B0, [0x039A]=0x1D6B1,
229        [0x039B]=0x1D6B2, [0x039C]=0x1D6B3, [0x039D]=0x1D6B4, [0x039E]=0x1D6B5, [0x039F]=0x1D6B6,
230        [0x03A0]=0x1D6B7, [0x03A1]=0x1D6B8, [0x03A3]=0x1D6BA, [0x03A4]=0x1D6BB, [0x03A5]=0x1D6BC,
231        [0x03A6]=0x1D6BD, [0x03A7]=0x1D6BE, [0x03A8]=0x1D6BF, [0x03A9]=0x1D6C0,
232        },
233    lcgreek   = {
234        [0x03B1]=0x1D6C2, [0x03B2]=0x1D6C3, [0x03B3]=0x1D6C4, [0x03B4]=0x1D6C5, [0x03B5]=0x1D6C6,
235        [0x03B6]=0x1D6C7, [0x03B7]=0x1D6C8, [0x03B8]=0x1D6C9, [0x03B9]=0x1D6CA, [0x03BA]=0x1D6CB,
236        [0x03BB]=0x1D6CC, [0x03BC]=0x1D6CD, [0x03BD]=0x1D6CE, [0x03BE]=0x1D6CF, [0x03BF]=0x1D6D0,
237        [0x03C0]=0x1D6D1, [0x03C1]=0x1D6D2, [0x03C2]=0x1D6D3, [0x03C3]=0x1D6D4, [0x03C4]=0x1D6D5,
238        [0x03C5]=0x1D6D6, [0x03C6]=0x1D6D7, [0x03C7]=0x1D6D8, [0x03C8]=0x1D6D9, [0x03C9]=0x1D6DA,
239        [0x03D1]=0x1D6DD, [0x03D5]=0x1D6DF, [0x03D6]=0x1D6E1, [0x03F0]=0x1D6DE, [0x03F1]=0x1D6E0,
240        [0x03F4]=0x1D6B9, [0x03F5]=0x1D6DC,
241    },
242    symbols   = {
243        [0x2202]=0x1D6DB, [0x2207]=0x1D6C1,
244        [0x0027]=0x2032, -- prime
245    },
246}
247
248local regular_bi = {
249    digits    = tovector(regular_bf.digits),
250    ucletters = toupper(0x1D468),
251    lcletters = tolower(0x1D482),
252    ucgreek   = {
253        [0x0391]=0x1D71C, [0x0392]=0x1D71D, [0x0393]=0x1D71E, [0x0394]=0x1D71F, [0x0395]=0x1D720,
254        [0x0396]=0x1D721, [0x0397]=0x1D722, [0x0398]=0x1D723, [0x0399]=0x1D724, [0x039A]=0x1D725,
255        [0x039B]=0x1D726, [0x039C]=0x1D727, [0x039D]=0x1D728, [0x039E]=0x1D729, [0x039F]=0x1D72A,
256        [0x03A0]=0x1D72B, [0x03A1]=0x1D72C, [0x03A3]=0x1D72E, [0x03A4]=0x1D72F, [0x03A5]=0x1D730,
257        [0x03A6]=0x1D731, [0x03A7]=0x1D732, [0x03A8]=0x1D733, [0x03A9]=0x1D734,
258        },
259    lcgreek   = {
260        [0x03B1]=0x1D736, [0x03B2]=0x1D737, [0x03B3]=0x1D738, [0x03B4]=0x1D739, [0x03B5]=0x1D73A,
261        [0x03B6]=0x1D73B, [0x03B7]=0x1D73C, [0x03B8]=0x1D73D, [0x03B9]=0x1D73E, [0x03BA]=0x1D73F,
262        [0x03BB]=0x1D740, [0x03BC]=0x1D741, [0x03BD]=0x1D742, [0x03BE]=0x1D743, [0x03BF]=0x1D744,
263        [0x03C0]=0x1D745, [0x03C1]=0x1D746, [0x03C2]=0x1D747, [0x03C3]=0x1D748, [0x03C4]=0x1D749,
264        [0x03C5]=0x1D74A, [0x03C6]=0x1D74B, [0x03C7]=0x1D74C, [0x03C8]=0x1D74D, [0x03C9]=0x1D74E,
265        [0x03D1]=0x1D751, [0x03D5]=0x1D753, [0x03D6]=0x1D755, [0x03F0]=0x1D752, [0x03F1]=0x1D754,
266        [0x03F4]=0x1D72D, [0x03F5]=0x1D750,
267    },
268    symbols   = {
269        [0x2202]=0x1D74F, [0x2207]=0x1D735,
270        [0x0027]=0x2032, -- prime
271    },
272}
273
274local regular = {
275    tf = regular_tf,
276    it = regular_it,
277    bf = regular_bf,
278    bi = regular_bi,
279}
280
281local sansserif_tf = {
282    digits    = todigit(0x1D7E2),
283    ucletters = toupper(0x1D5A0),
284    lcletters = tolower(0x1D5BA),
285    lcgreek   = tovector(regular_tf.lcgreek),
286    ucgreek   = tovector(regular_tf.ucgreek),
287    symbols   = tovector(regular_tf.symbols),
288}
289
290local sansserif_it = {
291    digits    = tovector(regular_tf.digits),
292    ucletters = toupper(0x1D608),
293    lcletters = tolower(0x1D622),
294    lcgreek   = tovector(regular_tf.lcgreek),
295    ucgreek   = tovector(regular_tf.ucgreek),
296    symbols   = tovector(regular_tf.symbols),
297}
298
299local sansserif_bf = {
300    digits    = todigit(0x1D7EC),
301    ucletters = toupper(0x1D5D4),
302    lcletters = tolower(0x1D5EE),
303    ucgreek   = {
304        [0x0391]=0x1D756, [0x0392]=0x1D757, [0x0393]=0x1D758, [0x0394]=0x1D759, [0x0395]=0x1D75A,
305        [0x0396]=0x1D75B, [0x0397]=0x1D75C, [0x0398]=0x1D75D, [0x0399]=0x1D75E, [0x039A]=0x1D75F,
306        [0x039B]=0x1D760, [0x039C]=0x1D761, [0x039D]=0x1D762, [0x039E]=0x1D763, [0x039F]=0x1D764,
307        [0x03A0]=0x1D765, [0x03A1]=0x1D766, [0x03A3]=0x1D768, [0x03A4]=0x1D769, [0x03A5]=0x1D76A,
308        [0x03A6]=0x1D76B, [0x03A7]=0x1D76C, [0x03A8]=0x1D76D, [0x03A9]=0x1D76E,
309        },
310    lcgreek   = {
311        [0x03B1]=0x1D770, [0x03B2]=0x1D771, [0x03B3]=0x1D772, [0x03B4]=0x1D773, [0x03B5]=0x1D774,
312        [0x03B6]=0x1D775, [0x03B7]=0x1D776, [0x03B8]=0x1D777, [0x03B9]=0x1D778, [0x03BA]=0x1D779,
313        [0x03BB]=0x1D77A, [0x03BC]=0x1D77B, [0x03BD]=0x1D77C, [0x03BE]=0x1D77D, [0x03BF]=0x1D77E,
314        [0x03C0]=0x1D77F, [0x03C1]=0x1D780, [0x03C2]=0x1D781, [0x03C3]=0x1D782, [0x03C4]=0x1D783,
315        [0x03C5]=0x1D784, [0x03C6]=0x1D785, [0x03C7]=0x1D786, [0x03C8]=0x1D787, [0x03C9]=0x1D788,
316        [0x03D1]=0x1D78B, [0x03D5]=0x1D78D, [0x03D6]=0x1D78F, [0x03F0]=0x1D78C, [0x03F1]=0x1D78E,
317        [0x03F4]=0x1D767, [0x03F5]=0x1D78A,
318    },
319    symbols   = {
320        [0x2202]=0x1D789, [0x2207]=0x1D76F,
321        [0x0027]=0x2032, -- prime
322    },
323}
324
325local sansserif_bi = {
326    digits    = tovector(sansserif_bf.digits),
327    ucletters = toupper(0x1D63C),
328    lcletters = tolower(0x1D656),
329    ucgreek   = {
330        [0x0391]=0x1D790, [0x0392]=0x1D791, [0x0393]=0x1D792, [0x0394]=0x1D793, [0x0395]=0x1D794,
331        [0x0396]=0x1D795, [0x0397]=0x1D796, [0x0398]=0x1D797, [0x0399]=0x1D798, [0x039A]=0x1D799,
332        [0x039B]=0x1D79A, [0x039C]=0x1D79B, [0x039D]=0x1D79C, [0x039E]=0x1D79D, [0x039F]=0x1D79E,
333        [0x03A0]=0x1D79F, [0x03A1]=0x1D7A0, [0x03A3]=0x1D7A2, [0x03A4]=0x1D7A3, [0x03A5]=0x1D7A4,
334        [0x03A6]=0x1D7A5, [0x03A7]=0x1D7A6, [0x03A8]=0x1D7A7, [0x03A9]=0x1D7A8,
335        },
336    lcgreek   = {
337        [0x03B1]=0x1D7AA, [0x03B2]=0x1D7AB, [0x03B3]=0x1D7AC, [0x03B4]=0x1D7AD, [0x03B5]=0x1D7AE,
338        [0x03B6]=0x1D7AF, [0x03B7]=0x1D7B0, [0x03B8]=0x1D7B1, [0x03B9]=0x1D7B2, [0x03BA]=0x1D7B3,
339        [0x03BB]=0x1D7B4, [0x03BC]=0x1D7B5, [0x03BD]=0x1D7B6, [0x03BE]=0x1D7B7, [0x03BF]=0x1D7B8,
340        [0x03C0]=0x1D7B9, [0x03C1]=0x1D7BA, [0x03C2]=0x1D7BB, [0x03C3]=0x1D7BC, [0x03C4]=0x1D7BD,
341        [0x03C5]=0x1D7BE, [0x03C6]=0x1D7BF, [0x03C7]=0x1D7C0, [0x03C8]=0x1D7C1, [0x03C9]=0x1D7C2,
342        [0x03D1]=0x1D7C5, [0x03D5]=0x1D7C7, [0x03D6]=0x1D7C9, [0x03F0]=0x1D7C6, [0x03F1]=0x1D7C8,
343        [0x03F4]=0x1D7A1, [0x03F5]=0x1D7C4,
344    },
345    symbols   = {
346        [0x2202]=0x1D7C3, [0x2207]=0x1D7A9,
347        [0x0027]=0x2032, -- prime
348    },
349}
350
351local sansserif = {
352    tf = sansserif_tf,
353    it = sansserif_it,
354    bf = sansserif_bf,
355    bi = sansserif_bi,
356}
357
358local monospaced_tf = {
359    digits    = todigit(0x1D7F6),
360    ucletters = toupper(0x1D670),
361    lcletters = tolower(0x1D68A),
362    lcgreek   = tovector(sansserif_tf.lcgreek),
363    ucgreek   = tovector(sansserif_tf.ucgreek),
364    symbols   = tovector(sansserif_tf.symbols),
365}
366
367local monospaced_it = tovector(sansserif_it)
368local monospaced_bf = tovector(sansserif_bf)
369local monospaced_bi = tovector(sansserif_bi)
370
371local monospaced = {
372    tf = monospaced_tf,
373    it = monospaced_tf,
374    bf = monospaced_tf,
375    bi = monospaced_bf,
376}
377
378local blackboard_tf = {
379    digits    = todigit(0x1D7D8),
380    ucletters = { -- C H N P Q R Z
381        [0x00041]=0x1D538, [0x00042]=0x1D539, [0x00043]=0x02102, [0x00044]=0x1D53B, [0x00045]=0x1D53C,
382        [0x00046]=0x1D53D, [0x00047]=0x1D53E, [0x00048]=0x0210D, [0x00049]=0x1D540, [0x0004A]=0x1D541,
383        [0x0004B]=0x1D542, [0x0004C]=0x1D543, [0x0004D]=0x1D544, [0x0004E]=0x02115, [0x0004F]=0x1D546,
384        [0x00050]=0x02119, [0x00051]=0x0211A, [0x00052]=0x0211D, [0x00053]=0x1D54A, [0x00054]=0x1D54B,
385        [0x00055]=0x1D54C, [0x00056]=0x1D54D, [0x00057]=0x1D54E, [0x00058]=0x1D54F, [0x00059]=0x1D550,
386        [0x0005A]=0x02124,
387    },
388    lcletters = {
389        -- tolower(0x1D552) :
390        [0x00061] = 0x1D552, [0x00062] = 0x1D553, [0x00063] = 0x1D554, [0x00064] = 0x1D555,
391        [0x00065] = 0x1D556, [0x00066] = 0x1D557, [0x00067] = 0x1D558, [0x00068] = 0x1D559,
392        [0x00069] = 0x1D55A, [0x0006A] = 0x1D55B, [0x0006B] = 0x1D55C, [0x0006C] = 0x1D55D,
393        [0x0006D] = 0x1D55E, [0x0006E] = 0x1D55F, [0x0006F] = 0x1D560, [0x00070] = 0x1D561,
394        [0x00071] = 0x1D562, [0x00072] = 0x1D563, [0x00073] = 0x1D564, [0x00074] = 0x1D565,
395        [0x00075] = 0x1D566, [0x00076] = 0x1D567, [0x00077] = 0x1D568, [0x00078] = 0x1D569,
396        [0x00079] = 0x1D56A, [0x0007A] = 0x1D56B,
397        -- arabic
398        [0x00628] = 0x1EEA1, [0x0062A] = 0x1EEB5, [0x0062B] = 0x1EEB6, [0x0062C] = 0x1EEA2,
399        [0x0062D] = 0x1EEA7, [0x0062E] = 0x1EEB7, [0x0062F] = 0x1EEA3, [0x00630] = 0x1EEB8,
400        [0x00631] = 0x1EEB3, [0x00632] = 0x1EEA6, [0x00633] = 0x1EEAE, [0x00634] = 0x1EEB4,
401        [0x00635] = 0x1EEB1, [0x00636] = 0x1EEB9, [0x00637] = 0x1EEA8, [0x00638] = 0x1EEBA,
402        [0x00639] = 0x1EEAF, [0x0063A] = 0x1EEBB, [0x00641] = 0x1EEB0, [0x00642] = 0x1EEB2,
403        [0x00644] = 0x1EEAB, [0x00645] = 0x1EEAC, [0x00646] = 0x1EEAD, [0x00648] = 0x1EEA5,
404        [0x0064A] = 0x1EEA9,
405    },
406    lcgreek   = { -- gamma pi
407        [0x03B3]=0x0213C, [0x03C0]=0x0213D,
408    },
409    ucgreek   = { -- Gamma pi
410        [0x0393]=0x0213E, [0x03A0]=0x0213F,
411    },
412    symbols   = { -- sum
413        [0x2211]=0x02140,
414        [0x0027]=0x2032, -- prime
415    },
416}
417
418blackboard_tf.lcgreek = merged(regular_tf.lcgreek, blackboard_tf.lcgreek)
419blackboard_tf.ucgreek = merged(regular_tf.ucgreek, blackboard_tf.ucgreek)
420blackboard_tf.symbols = merged(regular_tf.symbols, blackboard_tf.symbols)
421
422local blackboard = {
423    tf = blackboard_tf,
424    it = blackboard_tf,
425    bf = blackboard_tf,
426    bi = blackboard_tf,
427}
428
429local fraktur_tf= {
430    digits    = tovector(regular_tf.digits),
431    ucletters = { -- C H I R Z
432        [0x00041]=0x1D504, [0x00042]=0x1D505, [0x00043]=0x0212D, [0x00044]=0x1D507, [0x00045]=0x1D508,
433        [0x00046]=0x1D509, [0x00047]=0x1D50A, [0x00048]=0x0210C, [0x00049]=0x02111, [0x0004A]=0x1D50D,
434        [0x0004B]=0x1D50E, [0x0004C]=0x1D50F, [0x0004D]=0x1D510, [0x0004E]=0x1D511, [0x0004F]=0x1D512,
435        [0x00050]=0x1D513, [0x00051]=0x1D514, [0x00052]=0x0211C, [0x00053]=0x1D516, [0x00054]=0x1D517,
436        [0x00055]=0x1D518, [0x00056]=0x1D519, [0x00057]=0x1D51A, [0x00058]=0x1D51B, [0x00059]=0x1D51C,
437        [0x0005A]=0x02128,
438    },
439    lcletters = tolower(0x1D51E),
440    lcgreek   = tovector(regular_tf.lcgreek),
441    ucgreek   = tovector(regular_tf.ucgreek),
442    symbols   = tovector(regular_tf.symbols),
443}
444
445local fraktur_bf = {
446    digits    = tovector(regular_bf.digits),
447    ucletters = toupper(0x1D56C),
448    lcletters = tolower(0x1D586),
449    lcgreek   = tovector(regular_bf.lcgreek),
450    ucgreek   = tovector(regular_bf.ucgreek),
451    symbols   = tovector(regular_bf.symbols),
452}
453
454local fraktur = { -- ok
455    tf = fraktur_tf,
456    bf = fraktur_bf,
457    it = fraktur_tf,
458    bi = fraktur_bf,
459}
460
461local script_tf = {
462    digits    = tovector(regular_tf.digits),
463    ucletters = { -- B E F H I L M R -- P 2118
464        [0x00041]=0x1D49C, [0x00042]=0x0212C, [0x00043]=0x1D49E, [0x00044]=0x1D49F, [0x00045]=0x02130,
465        [0x00046]=0x02131, [0x00047]=0x1D4A2, [0x00048]=0x0210B, [0x00049]=0x02110, [0x0004A]=0x1D4A5,
466        [0x0004B]=0x1D4A6, [0x0004C]=0x02112, [0x0004D]=0x02133, [0x0004E]=0x1D4A9, [0x0004F]=0x1D4AA,
467        [0x00050]=0x1D4AB, [0x00051]=0x1D4AC, [0x00052]=0x0211B, [0x00053]=0x1D4AE, [0x00054]=0x1D4AF,
468        [0x00055]=0x1D4B0, [0x00056]=0x1D4B1, [0x00057]=0x1D4B2, [0x00058]=0x1D4B3, [0x00059]=0x1D4B4,
469        [0x0005A]=0x1D4B5,
470    },
471    lcletters = { -- E G O -- L 2113
472        [0x00061]=0x1D4B6, [0x00062]=0x1D4B7, [0x00063]=0x1D4B8, [0x00064]=0x1D4B9, [0x00065]=0x0212F,
473        [0x00066]=0x1D4BB, [0x00067]=0x0210A, [0x00068]=0x1D4BD, [0x00069]=0x1D4BE, [0x0006A]=0x1D4BF,
474        [0x0006B]=0x1D4C0, [0x0006C]=0x1D4C1, [0x0006D]=0x1D4C2, [0x0006E]=0x1D4C3, [0x0006F]=0x02134,
475        [0x00070]=0x1D4C5, [0x00071]=0x1D4C6, [0x00072]=0x1D4C7, [0x00073]=0x1D4C8, [0x00074]=0x1D4C9,
476        [0x00075]=0x1D4CA, [0x00076]=0x1D4CB, [0x00077]=0x1D4CC, [0x00078]=0x1D4CD, [0x00079]=0x1D4CE,
477        [0x0007A]=0x1D4CF,
478    },
479    lcgreek = tovector(regular_tf.lcgreek),
480    ucgreek = tovector(regular_tf.ucgreek),
481    symbols = tovector(regular_tf.symbols),
482}
483
484local script_bf = {
485    digits    = tovector(regular_bf.digits),
486    ucletters = toupper(0x1D4D0),
487    lcletters = tolower(0x1D4EA),
488    lcgreek   = tovector(regular_bf.lcgreek),
489    ucgreek   = tovector(regular_bf.ucgreek),
490    symbols   = tovector(regular_bf.symbols),
491}
492
493local script = {
494    tf = script_tf,
495    bf = script_bf,
496    it = script_tf,
497    bi = script_bf,
498}
499
500local alphabets = allocate {
501    regular    = regular,
502    sansserif  = sansserif,
503    monospaced = monospaced,
504    blackboard = blackboard,
505    fraktur    = fraktur,
506    script     = script,
507}
508
509alphabets.tt          = tovector(monospaced)
510alphabets.ss          = tovector(sansserif)
511alphabets.rm          = tovector(regular)
512alphabets.bb          = tovector(blackboard)
513alphabets.fr          = tovector(fraktur)
514alphabets.sr          = tovector(script)
515
516monospaced.normal     = tovector(monospaced_tf)
517monospaced.italic     = tovector(monospaced_it)
518monospaced.bold       = tovector(monospaced_bf)
519monospaced.bolditalic = tovector(monospaced_bi)
520
521sansserif.normal      = tovector(sansserif_tf)
522sansserif.italic      = tovector(sansserif_it)
523sansserif.bold        = tovector(sansserif_bf)
524sansserif.bolditalic  = tovector(sansserif_bi)
525
526regular.normal        = tovector(regular_tf)
527regular.italic        = tovector(regular_it)
528regular.bold          = tovector(regular_bf)
529regular.bolditalic    = tovector(regular_bi)
530
531alphabets.serif       = tovector(regular)
532alphabets.type        = tovector(monospaced)
533alphabets.teletype    = tovector(monospaced)
534
535mathematics.alphabets = alphabets
536
537local mathremap       = allocate { }
538mathematics.mapremap  = mathremap
539
540local boldmap         = allocate { }
541mathematics.boldmap   = boldmap
542
543-- all math (a bit of redundancy here) (sorted for tracing)
544
545for alphabet, styles in sortedhash(alphabets) do -- per 9/6/2011 we also have attr for missing
546    for style, data in sortedhash(styles) do
547     -- let's keep the long names (for tracing)
548        local n = #mathremap + 1
549        local d = {
550            attribute = n,
551            alphabet  = alphabet,
552            style     = style,
553        }
554        styles[style] = d
555        setmetatableindex(d,data) -- we could use a alphadata table
556        mathremap[n] = d
557    end
558end
559
560-- bold math
561
562local function remapbold(tf,bf)
563    local styles = mathematics.styles
564    local sets   = mathematics.sets
565    for i=1,#styles do
566        for j=1,#sets do
567            local one = styles[i]
568            local two = sets[j]
569            local a  = alphabets[one]
570            local tf = a[tf][two]
571            local bf = a[bf][two]
572            if tf and bf then
573                for k, v in next, tf do
574                    boldmap[v] = bf[k]
575                end
576            end
577        end
578    end
579end
580
581remapbold("tf","bf")
582remapbold("it","bi")
583
584-- table.save("e:/tmp/a.lua",alphabets)
585-- table.save("e:/tmp/b.lua",boldmap)
586
587function mathematics.tostyle(attribute)
588    local r = mathremap[attribute]
589    return r and r.style or "tf"
590end
591
592function mathematics.toname(attribute)
593    local r = mathremap[attribute]
594    return r and r.alphabet or "regular"
595end
596
597-- of course we could do some div/mod trickery instead
598
599local mathalphabet = attributes.private("mathalphabet")
600
601function mathematics.getboth(alphabet,style)
602    local data = alphabet and alphabets[alphabet] or regular
603    data = data[style or "tf"] or data.tf
604    return data and data.attribute
605end
606
607function mathematics.getstyle(style)
608    local r = mathremap[texgetattribute(mathalphabet)]
609    local alphabet = r and r.alphabet or "regular"
610    local data = alphabets[alphabet][style]
611    return data and data.attribute
612end
613
614function mathematics.syncboth(alphabet,style)
615    local data = alphabet and alphabets[alphabet] or regular
616    data = style and data[style] or data.tf
617    texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
618end
619
620function mathematics.syncstyle(style)
621    local r = mathremap[texgetattribute(mathalphabet)]
622    local alphabet = r and r.alphabet or "regular"
623    local data = alphabets[alphabet][style]
624    texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
625end
626
627function mathematics.syncname(alphabet)
628 -- local r = mathremap[mathalphabet]
629    local r = mathremap[texgetattribute(mathalphabet)]
630    local style = r and r.style or "tf"
631    local data = alphabets[alphabet][style]
632    texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
633end
634
635implement {
636    name      = "setmathattribute",
637    arguments = "2 strings",
638    actions   = function(alphabet,style)
639        local data = alphabets[alphabet] or regular
640        data = data[style] or data.tf
641        texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
642    end
643}
644
645implement {
646    name      = "setmathstyle",
647    arguments = "string",
648    actions   = function(style)
649        local r = mathremap[texgetattribute(mathalphabet)]
650        local alphabet = r and r.alphabet or "regular"
651        local data = alphabets[alphabet][style]
652        texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
653    end
654}
655
656implement {
657    name      = "setmathalphabet",
658    arguments = "string",
659    actions   = function(alphabet)
660     -- local r = mathremap[mathalphabet]
661        local r = mathremap[texgetattribute(mathalphabet)]
662        local style = r and r.style or "tf"
663        local data = alphabets[alphabet][style]
664        texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
665    end
666}
667
668local islcgreek = regular_tf.lcgreek
669local isucgreek = regular_tf.ucgreek
670local issygreek = regular_tf.symbols
671local isgreek   = merged(islcgreek,isucgreek,issygreek)
672
673local greekremapping = {
674    { what = "unchanged" }, -- upright
675    { what = "upright", it = "tf", bi = "bf" }, -- upright
676    { what = "italic",  tf = "it", bf = "bi" }, -- italic
677}
678
679local usedremap = { }
680
681local function resolver(map)
682    return function (t,k)
683        local v =
684            map.digits   [k] or
685            map.lcletters[k] or map.ucletters[k] or
686            map.lcgreek  [k] or map.ucgreek  [k] or
687            map.symbols  [k] or k
688        t[k] = v
689        return v
690    end
691end
692
693for k, v in next, mathremap do
694    local t = { }
695    setmetatableindex(t,resolver(v))
696    usedremap[k] = t
697end
698
699local function remapgreek(mathalphabet,how,detail,char)
700    local r = mathremap[mathalphabet] -- what if 0
701    local alphabet = r and r.alphabet or "regular"
702    local style = r and r.style or "tf"
703    local remapping = greekremapping[how]
704    if trace_greek then
705        report_remapping("greek %s, %s char %C, alphabet %a %a, method %a","before",detail,char,alphabet,style,remapping.what)
706    end
707    local newstyle = remapping[style]
708    if newstyle then
709        local data = alphabets[alphabet][newstyle] -- always something
710        mathalphabet = data and data.attribute or mathalphabet
711        style        = newstyle
712    end
713    if trace_greek then
714        report_remapping("greek %s, %s char %C, alphabet %a %a, method %a","after",detail,char,alphabet,style,remapping.what)
715    end
716    return mathalphabet, style
717end
718
719function mathematics.remapalphabets(char,mathalphabet,mathgreek)
720    if not mathalphabet then
721        return
722    end
723    if mathgreek and mathgreek > 0 then
724        if not isgreek[char] then
725            -- nothing needed
726        elseif islcgreek[char] then
727            local lc = extract(mathgreek,4,4) --  (mathgreek >> 4) & ~(-1 << 4)
728            if lc > 1 then
729                mathalphabet = remapgreek(mathalphabet,lc,"lowercase",char)
730            end
731        elseif isucgreek[char] then
732            local uc = extract(mathgreek,0,4) --  (mathgreek >> 0) & ~(-1 << 4)
733            if uc > 1 then
734                mathalphabet = remapgreek(mathalphabet,uc,"uppercase",char)
735            end
736        elseif issygreek[char] then
737            local sy = extract(mathgreek,8,4) --  (mathgreek >> 8) & ~(-1 << 4)
738            if sy > 1 then
739                mathalphabet = remapgreek(mathalphabet,sy,"symbol",char)
740            end
741        end
742    end
743    if mathalphabet > 0 then
744        local remap = usedremap[mathalphabet] -- redundant check
745        if remap then
746            local newchar = remap[char]
747            return newchar ~= char and newchar
748        end
749    end
750 -- return nil
751end
752
753-- begin of experiment
754
755local fallback = {
756    tf = "bf",
757    it = "bi",
758    bf = "tf",
759    bi = "it",
760}
761
762function mathematics.fallbackstyleattr(attribute)
763    local r = mathremap[attribute]
764    local alphabet = r.alphabet or "regular"
765    local style = r.style or "tf"
766    local fback = fallback[style]
767    if fback then
768        local data = alphabets[alphabet][fback]
769        if data then
770            local attr = data.attribute
771            return attribute ~= attr and attr
772        end
773    end
774end
775
776-- end of experiment
777
778local function checkedcopy(characters,child,parent)
779    for k, v in next, child do
780        if not characters[v] then
781            characters[v] = characters[parent[k]]
782        end
783    end
784end
785
786function mathematics.addfallbacks(main)
787    local characters = main.characters
788    checkedcopy(characters,regular.bf.ucgreek,regular.tf.ucgreek)
789    checkedcopy(characters,regular.bf.lcgreek,regular.tf.lcgreek)
790    checkedcopy(characters,regular.bi.ucgreek,regular.it.ucgreek)
791    checkedcopy(characters,regular.bi.lcgreek,regular.it.lcgreek)
792end
793