1if not modules then modules = { } end modules ['font-imp-scripts'] = {
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 getrange = characters.getrange
10
11local settings_to_hash = utilities.parsers.settings_to_hash
12
13if not context then return end
14
15
16
17local next, type, tonumber = next, type, tonumber
18local gmatch = string.gmatch
19local max = math.max
20
21local fonts = fonts
22local utilities = utilities
23
24local helpers = fonts.helpers
25local charcommand = helpers.commands.char
26local downcommand = helpers.commands.down
27local upcommand = helpers.commands.up
28
29local handlers = fonts.handlers
30local otf = handlers.otf
31local afm = handlers.afm
32local registerotffeature = otf.features.register
33local registerafmfeature = afm.features.register
34local addotffeature = otf.addfeature
35
36local settings_to_hash = utilities.parsers.settings_to_hash
37local sortedhash = table.sortedhash
38
39local handlers = fonts.handlers
40
41local sup = nil
42local sub = nil
43
44local function initialize(tfmdata,key,value)
45
46 if not sup then
47 sup = { }
48 sub = { }
49 for unicode, data in next, characters.data do
50 local specials = data.specials
51 if specials then
52 local what = specials[1]
53 if what == "super" then
54 sup[unicode] = specials[2]
55 elseif what == "sub" then
56 sub[unicode] = specials[2]
57 end
58 end
59 end
60 end
61
62 local spec
63 if value == true then
64 spec = { factor = 3/5, up = 5/4, down = 1/4 }
65 elseif type(value) == "number" then
66 spec = { factor = value, up = 5/4, down = 1/4 }
67 else
68 spec = settings_to_hash(value)
69 end
70 local factor = tonumber(spec.factor) or 3/5
71 local up = tonumber(spec.up) or 5/4
72 local down = tonumber(spec.down) or 1/4
73
74 local characters = tfmdata.characters
75 local parameters = tfmdata.parameters
76 local up = parameters.xheight * up
77 local down = -parameters.xheight * down
78
79 local function add(unicode,other,go_up)
80 local old = characters[other]
81 if old then
82 local shift = go_up and up or down
83 local width = (old.width or 0) * factor
84 local height = (old.height or 0) * factor + shift
85 local depth = go_up and 0 or max((old.depth or 0) * factor + down,0)
86 characters[unicode] = {
87 width = width,
88 height = height,
89 depth = depth,
90 commands = { { "offset", 0, shift, other, factor, factor } },
91
92
93
94
95 }
96 end
97 end
98 for unicode, other in sortedhash(sup) do
99 add(unicode,other,true)
100 end
101 for unicode, other in sortedhash(sub) do
102 add(unicode,other,false)
103 end
104end
105
106local specification = {
107 name = "scripts",
108 description = "add superiors and inferiors",
109 manipulators = {
110 base = initialize,
111 node = initialize,
112 }
113}
114
115registerotffeature(specification)
116registerafmfeature(specification)
117
118
119
120local function initialize(tfmdata,key,value)
121 if value then
122 local detail = type(value) == "string" and settings_to_hash(value) or { }
123 local orientation = tonumber(detail.orientation) or 0
124 if orientation == 1 or orientation == 3 then
125 local characters = tfmdata.characters
126 local parameters = tfmdata.parameters
127 local emwidth = parameters.quad
128 local exheight = parameters.xheight
129 local ranges = detail.ranges
130 local downshift = exheight * (tonumber(detail.down) or 0)
131 local rightshift = exheight * (tonumber(detail.right) or 0)
132 local orientate
133 if orientation == 1 then
134 orientate = function(character)
135 local width = character.width or 0
136 local height = character.height or 0
137 local depth = character.depth or 0
138 character.width = height + depth + rightshift + rightshift
139 character.height = width - downshift
140 character.depth = shift
141 character.xoffset = depth + rightshift
142 character.yoffset = width - downshift
143 character.orientation = orientation
144 end
145 else
146 orientate = function(character)
147 local width = character.width or 0
148 local height = character.height or 0
149 local depth = character.depth or 0
150
151 character.height = width - downshift
152 character.depth = shift
153
154
155
156 end
157 end
158 if ranges then
159 for s in gmatch(ranges,"[^, ]+") do
160 local start, stop, description, gaps = getrange(s,true)
161 if start and stop then
162 for unicode=start,stop do
163 local character = characters[unicode]
164 if character then
165 orientate(character)
166 end
167 end
168 end
169 end
170 else
171 for unicode, character in next, characters do
172 orientate(character)
173 end
174 end
175 end
176 end
177end
178
179local specification = {
180 name = "vertical",
181 description = "vertical",
182 manipulators = {
183 base = initialize,
184 node = initialize,
185 }
186}
187
188registerotffeature(specification)
189registerafmfeature(specification)
190
191do
192
193
194
195 local left <const> = 1
196 local middle <const> = 2
197 local right <const> = 3
198
199 local mapping = {
200 [0x02010] = middle,
201 [0x02027] = middle,
202 [0x02329] = left,
203 [0x0232A] = right,
204 [0x03001] = right,
205 [0x03002] = right,
206 [0x03008] = left,
207 [0x03009] = right,
208 [0x0300A] = left,
209 [0x0300B] = right,
210 [0x0300C] = left,
211 [0x0300D] = right,
212 [0x0300E] = left,
213 [0x0300F] = right,
214 [0x03010] = left,
215 [0x03011] = right,
216 [0x03014] = left,
217 [0x03015] = right,
218 [0x03016] = left,
219 [0x03017] = right,
220 [0x03018] = left,
221 [0x03019] = right,
222 [0x0301A] = left,
223 [0x0301B] = right,
224 [0x0301D] = left,
225 [0x0301E] = right,
226 [0x0301F] = right,
227 [0x030FB] = middle,
228 [0x0FF01] = middle,
229 [0x0FF02] = middle,
230 [0x0FF07] = middle,
231 [0x0FF08] = left,
232 [0x0FF09] = right,
233 [0x0FF0C] = right,
234 [0x0FF0E] = right,
235 [0x0FF1A] = middle,
236 [0x0FF1B] = middle,
237 [0x0FF3B] = left,
238 [0x0FF3D] = right,
239 [0x0FF5B] = left,
240 [0x0FF5C] = middle,
241 [0x0FF5D] = right,
242 [0x0FF5F] = left,
243 [0x0FF60] = right,
244 [0x0FFE4] = middle,
245
246 [0xF054C] = left,
247 [0xF054D] = right,
248 [0xF054E] = left,
249 [0xF054F] = right,
250 }
251
252 local firstprivate <const> = fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
253
254 addotffeature {
255 name = "halt",
256 type = "single",
257 data = function(tfmdata)
258 local resources = tfmdata.resources
259 if not resources then
260 return
261 end
262 local features = resources.features
263 if not features then
264 return
265 end
266 local gpos = features.gpos
267 if gpos and gpos.halt then
268 return
269 end
270 local descriptions = tfmdata.descriptions
271 if not descriptions[0x3002] then
272
273 return
274 end
275 local positions = { }
276 local reposition
277 for u, v in next, mapping do
278 local d = descriptions[u]
279 if d then
280 if not reposition then
281 local w = d.width
282 reposition = {
283 { -w/2, 0, -w/2, 0 },
284 { -w/4, 0, -w/2, 0 },
285 { 0, 0, -w/2, 0 },
286 }
287 end
288 positions[u] = reposition[v]
289 else
290
291 end
292 end
293 if reposition then
294 local p = firstprivate
295 while true do
296 local d = descriptions[p]
297 if d then
298 local v = mapping[d.unicode or 0]
299 if v then
300 positions[p] = reposition[v]
301 end
302 p = p + 1
303 else
304 break
305 end
306 end
307 end
308 return next(positions) and positions
309 end,
310 }
311
312end
313 |