1if not modules then modules = { } end modules ['back-imp-lua'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to back-imp-lua.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
11
12local fontproperties = fonts.hashes.properties
13local fontparameters = fonts.hashes.parameters
14local fontshapes = fonts.hashes.shapes
15
16local starttiming = statistics.starttiming
17local stoptiming = statistics.stoptiming
18
19local texgetbox = tex.getbox
20
21local bpfactor <const> = number.dimenfactors.bp
22
23local rulecodes <const> = nodes.rulecodes
24local normalrule_code <const> = rulecodes.normal
25
26
27
28
29
30
31
32
33local outlinerule_code <const> = rulecodes.outline
34
35
36
37local pages = { }
38local fonts = { }
39local names = { }
40local mapping = { }
41local used = { }
42local shapes = { }
43local glyphs = { }
44local buffer = { }
45local metadata = nil
46local b = 0
47local converter = nil
48
49local compact = false
50local shapestoo = true
51
52local x, y, d, f, c, w, h, t, r, o
53
54local function reset()
55 buffer = { }
56 b = 0
57 t = nil
58 x = nil
59 y = nil
60 d = nil
61 f = nil
62 c = nil
63 w = nil
64 h = nil
65 r = nil
66 o = nil
67end
68
69local function result()
70 return {
71 metadata = metadata,
72 fonts = fonts,
73 pages = pages,
74 shapes = shapes,
75 }
76end
77
78
79
80local function outputfilename(driver)
81 return tex.jobname .. "-output.lua"
82end
83
84local function save()
85 local filename = outputfilename()
86 drivers.report("saving result in %a",filename)
87 starttiming(drivers)
88 local data = result()
89 if data then
90 io.savedata(filename,table.serialize(data))
91 end
92 stoptiming(drivers)
93end
94
95local function prepare(driver)
96 converter = drivers.converters.lmtx
97
98 backends.initialize("lua")
99
100 luatex.registerstopactions(1,function()
101 save()
102 end)
103end
104
105local function initialize(driver,details)
106 reset()
107end
108
109local function finalize(driver,details)
110 local n = details.pagenumber
111 local b = details.boundingbox
112 pages[n] = {
113 number = n,
114 content = buffer,
115 boundingbox = {
116 b[1] * bpfactor,
117 b[2] * bpfactor,
118 b[3] * bpfactor,
119 b[4] * bpfactor,
120 },
121 }
122 if not metadata then
123
124
125 local identity = interactions.general.getidentity()
126 local jobname = environment.jobname or tex.jobname or "unknown"
127 metadata = {
128 unit = "bp",
129 jobname = jobname,
130 title = identity.title,
131 subject = identity.subject,
132 author = identity.author,
133 keywords = identity.keywords,
134 time = os.date("%Y-%m-%d %H:%M"),
135 engine = environment.luatexengine .. " " .. environment.luatexversion,
136 context = environment.version,
137 }
138 end
139end
140
141local function wrapup(driver)
142end
143
144local function cleanup(driver)
145 reset()
146end
147
148local function convert(driver,boxnumber,pagenumber)
149 converter(driver,texgetbox(boxnumber),"page",pagenumber)
150end
151
152
153
154local function updatefontstate(id)
155 if not mapping[id] then
156 local fn = #fonts + 1
157 mapping[id] = fn
158 local properties = fontproperties[id]
159 local parameters = fontparameters[id]
160 local filename = file.basename(properties.filename)
161 local fontname = properties.fullname or properties.fontname
162 if shapestoo then
163 if not names[fontname] then
164 local sn = #shapes+1
165 names[fontname] = sn
166 shapes[sn] = { }
167 glyphs[sn] = fontshapes[id].glyphs
168 end
169 end
170 fonts[fn] = {
171 filename = filename,
172 name = fontname,
173 size = parameters.size * bpfactor,
174 shapes = shapestoo and names[fontname] or nil,
175 }
176 end
177end
178
179local function flushcharacter(current, pos_h, pos_v, pos_r, font, char)
180 local fnt = mapping[font]
181 b = b + 1
182 buffer[b] = {
183 t = "glyph" ~= t and "glyph" or nil,
184 f = font ~= f and fnt or nil,
185 c = char ~= c and char or nil,
186 x = pos_h ~= x and (pos_h * bpfactor) or nil,
187 y = pos_v ~= y and (pos_v * bpfactor) or nil,
188 d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
189 }
190 t = "glyph"
191 f = font
192 c = char
193 x = pos_h
194 y = pos_v
195 d = pos_r
196 if shapestoo then
197
198 local sn = fonts[fnt].shapes
199 local shp = shapes[sn]
200 if not shp[char] then
201 shp[char] = glyphs[sn][char]
202 end
203 end
204end
205
206local function flush_rule(current, pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
207 b = b + 1
208 buffer[b] = {
209 t = "rule" ~= t and "rule" or nil,
210 r = rule_s ~= r and rule_s or nil,
211 o = rule_s == "outline" and rule_o ~= o and (rule_o * bpfactor) or nil,
212 w = size_h ~= w and (size_h * bpfactor) or nil,
213 h = size_v ~= h and (size_v * bpfactor) or nil,
214 x = pos_h ~= x and (pos_h * bpfactor) or nil,
215 y = pos_v ~= y and (pos_v * bpfactor) or nil,
216 d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
217 }
218 t = "rule"
219 w = size_h
220 h = size_v
221 x = pos_h
222 y = pos_v
223 d = pos_r
224end
225
226local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
227 local rule_s, rule_o
228 if subtype == normalrule_code then
229 rule_s = normal_rule_code
230 elseif subtype == outlinerule_code then
231 rule_s = outline_rule_code
232 rule_o = getdata(current)
233 else
234 return
235 end
236 return flush_rule(pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
237end
238
239local function flushsimplerule(pos_h, pos_v, pos_r, size_h, size_v)
240 return flush_rule(false,pos_h,pos_v,pos_r,size_h,size_v,normalrule_code,nil)
241end
242
243local function flushspecialrule(pos_h, pos_v, pos_r, w, h, d, l, outline)
244 return flush_rule(false,pos_h,pos_v-d,pos_r,w,h+d,outline and outlinerule_code or normalrule_code)
245end
246
247
248
249
250
251
252
253drivers.install {
254 name = "lua",
255 actions = {
256 prepare = prepare,
257 initialize = initialize,
258 finalize = finalize,
259 wrapup = wrapup,
260 cleanup = cleanup,
261 convert = convert,
262 outputfilename = outputfilename,
263 },
264 flushers = {
265 updatefontstate = updatefontstate,
266 character = flushcharacter,
267 rule = flushrule,
268 simplerule = flushsimplerule,
269 specialrule = flushspecialrule,
270 }
271}
272
273
274
275local function outputfilename(driver)
276 return tex.jobname .. "-output.json"
277end
278
279local function save()
280 local filename = outputfilename()
281 drivers.report("saving result in %a",filename)
282 starttiming(drivers)
283 local data = result()
284 if data then
285 if not utilities.json then
286 require("util-jsn")
287 end
288 io.savedata(filename,utilities.json.tostring(data,not compact))
289 end
290 stoptiming(drivers)
291end
292
293local function prepare(driver)
294 converter = drivers.converters.lmtx
295 luatex.registerstopactions(1,function()
296 save()
297 end)
298end
299
300
301
302drivers.install {
303 name = "json",
304 actions = {
305 prepare = prepare,
306 wrapup = wrapup,
307 cleanup = cleanup,
308
309 initialize = initialize,
310 convert = convert,
311 finalize = finalize,
312
313 outputfilename = outputfilename,
314 },
315 flushers = {
316 updatefontstate = updatefontstate,
317 character = flushcharacter,
318 rule = flushrule,
319 simplerule = flushsimplerule,
320 specialrule = flushspecialrule,
321 setstate = function() end,
322 }
323}
324
325
326
327local function outputfilename(driver)
328 return tex.jobname .. "-output.js"
329end
330
331local function save()
332 local filename = outputfilename()
333 drivers.report("saving result in %a",filename)
334 starttiming(drivers)
335 local data = result()
336 if data then
337 if not utilities.json then
338 require("util-jsn")
339 end
340 io.savedata(filename,
341 "const JSON_CONTEXT = JSON.parse ( `" ..
342 utilities.json.tostring(data,not compact) ..
343 "` ) ;\n"
344 )
345 end
346 stoptiming(drivers)
347end
348
349local function prepare(driver)
350 converter = drivers.converters.lmtx
351
352 backends.initialize("js")
353
354 luatex.registerstopactions(1,function()
355 save()
356 end)
357end
358
359
360
361drivers.install {
362 name = "js",
363 actions = {
364 prepare = prepare,
365 initialize = initialize,
366 finalize = finalize,
367 wrapup = wrapup,
368 cleanup = cleanup,
369 convert = convert,
370 outputfilename = outputfilename,
371 },
372 flushers = {
373 updatefontstate = updatefontstate,
374 character = flushcharacter,
375 rule = flushrule,
376 simplerule = flushsimplerule,
377 specialrule = flushspecialrule,
378 }
379}
380 |