1if not modules then modules = { } end modules ['font-mpf'] = {
2 version = 1.001,
3 comment = "companion to font-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local formatters = string.formatters
10local sortedhash = table.sortedhash
11
12local addcharacters = fonts.constructors.addcharacters
13local fontdata = fonts.hashes.identifiers
14local fontchars = fonts.hashes.characters
15
16local otf = fonts.handlers.otf
17local otfregister = otf.features.register
18
19
20
21local register = fonts.collections.register
22local checkenabled = fonts.collections.checkenabled
23local newprivateslot = fonts.helpers.newprivateslot
24
25local currentfont = font.current
26
27
28
29local makesetups = formatters["box:%s:%S"]
30
31local a_exportstatus = attributes.private('exportstatus')
32
33local function makeglyphbox(char,spec)
34 token.expand_macro("makeglyphbox",true,spec.setups or tostring(char))
35 local b = tex.takebox("glyphbox")
36
37 spec.code = {
38 width = b.width,
39 height = b.height,
40 depth = b.depth,
41 objnum = tex.boxresources.save(b,nil,nil,true),
42 }
43end
44
45local function setboxglyphs(category,fontid,unicode,specification)
46 local box = specification.code
47 if unicode and box then
48 local tfmdata = fontdata[fontid]
49 local characters = tfmdata.characters
50 local newdata = {
51 width = box.width or 0,
52 height = box.height or 0,
53 depth = box.depth or 0,
54 unicode = unicode,
55 }
56
57 characters[unicode] = newdata
58
59 fonts.dropins.swapone("box",tfmdata,specification,unicode)
60
61 addcharacters(fontid, { characters = { [unicode] = newdata } })
62 return fontid, unicode
63 else
64 logs.report("box glyph", "invalid glyph box for %C",unicode)
65 end
66end
67
68local function setboxglyph(specification)
69 if specification then
70 local name = specification.name
71 local unicode = specification.unicode
72 local font = currentfont()
73 if not unicode and name then
74 unicode = newprivateslot(name)
75 specification.unicode = unicode
76 end
77 if unicode then
78 if not specification.setups then
79 specification.setups = name
80 end
81
82 register(font,unicode,function(font,private)
83 makeglyphbox(unicode,specification)
84 return setboxglyphs(category,font,unicode,specification)
85 end)
86 checkenabled()
87 end
88 end
89end
90
91local function setboxdirectly(font,unicode,box,expose)
92 if box then
93 local tfmdata = fontdata[font]
94 local glyphboxes = (tfmdata.glyphboxes or 0) + 1
95 tfmdata.glyphboxes = glyphboxes
96 local private = newprivateslot(formatters["BG:%05X"](glyphboxes))
97
98 local newdata = {
99 width = box.width or 0,
100 height = box.height or 0,
101 depth = box.depth or 0,
102 unicode = unicode,
103 objnum = tex.boxresources.save(box,nil,nil,true),
104 expose = expose,
105 }
106 local specification = {
107 code = newdata
108 }
109 tfmdata.characters[private] = newdata
110 addcharacters(font, { characters = { [private] = newdata } })
111 fonts.dropins.swapone("box",tfmdata,specification,private)
112 checkenabled()
113 return private
114 end
115end
116
117fonts.helpers.setboxdirectly = setboxdirectly
118
119local boxes = table.setmetatableindex("table")
120
121function fonts.helpers.registerglyphbox(specification)
122 local category = specification.category
123 local whatever = specification.unicode or specification.name
124 if category and whatever then
125 boxes[category][whatever] = { action = makeglyphbox }
126 end
127end
128
129local function initializebox(tfmdata,kind,value)
130 local boxes = boxes[value]
131 if value then
132 local font = tfmdata.properties.id
133
134 for char, spec in sortedhash(boxes) do
135 spec.setups = makesetups(value,char)
136 if type(char) == "string" then
137 char = newprivateslot(name)
138 end
139
140 register(font,char,function(font,char)
141 local action = spec.action
142 if type(action) == "function" then
143 action(char,spec)
144 end
145 return setboxglyphs(value,font,char,spec)
146 end)
147 end
148 checkenabled()
149 end
150end
151
152fonts.helpers.setboxglyphs = setboxglyphs
153fonts.helpers.setboxglyph = setboxglyph
154
155interfaces.implement {
156 name = "registerboxglyph",
157 public = true,
158 protected = true,
159 actions = fonts.helpers.registerglyphbox,
160 arguments = { {
161 { "category" },
162 { "unicode", "integer" },
163 { "name" },
164 } },
165}
166
167interfaces.implement {
168 name = "setboxglyph",
169 public = true,
170 protected = true,
171 actions = setboxglyph,
172 arguments = { {
173 { "category" },
174 { "unicode", "integer" },
175 { "name" },
176 { "*" }
177 } },
178}
179
180fonts.handlers.otf.features.register {
181 name = "box",
182 description = "box glyphs",
183 manipulators = {
184 base = initializebox,
185 node = initializebox,
186 }
187}
188
189
190
191
192
193
194local fontcallbacks = fonts.callbacks or { }
195fonts.callbacks = fontcallbacks
196
197function fontcallbacks.devirtualize(chardata,f,c)
198 if chardata.commands then
199 local h = node.hpack(nodes.pool.glyph(f,c))
200 local p = setboxdirectly(f,c,h)
201 chardata.oldcommands = chardata.commands
202 chardata.commands = { { "char", p } }
203 chardata.callback = false
204 end
205end
206
207local function processcallback(f,c)
208 local characters = fontchars[f]
209 local chardata = characters[c]
210 if chardata then
211 local callback = chardata.callback
212 if callback then
213 local action = type(callback) == "function" and callback or fontcallbacks[callback]
214 if action then
215 action(chardata,f,c)
216 end
217 end
218 end
219end
220
221callbacks.register("process_character",processcallback,"apply an action to a character in a font")
222
223fontcallbacks.callback = processcallback
224 |