meta-blb.lua /size: 8262 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['meta-blb'] = {
2    version   = 1.001,
3    comment   = "companion to mlib-ctx.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
9-- This could be integrated in other modules but for me it also serves
10-- as an example of usign the plugin mechanism.
11
12local tonumber = tonumber
13
14local setmetatableindex = table.setmetatableindex
15local insert, remove = table.insert, table.remove
16local formatters = string.formatters
17
18local topoints        = number.topoints
19local mpprint         = mp.print
20local mpinteger       = mp.integer
21local mppoints        = mp.points
22local mptriplet       = mp.triplet
23local mptripletpoints = mp.tripletpoints
24
25local nuts            = nodes.nuts
26local hpack           = nuts.hpack
27local setbox          = nuts.setbox
28local getwhd          = nuts.getwhd
29local getwidth        = nuts.getwidth
30local toutf           = nuts.toutf
31
32local trace           = false
33local report          = logs.reporter("metapost","blobs")
34
35trackers.register("metapost.blobs", function(v) trace = v end)
36
37local allblobs = { }
38
39local function newcategory(t,k)
40    if trace then
41        report("new category %a",k)
42    end
43    local v = {
44        name  = k,
45        text  = "",
46        blobs = { },
47    }
48    t[k] = v
49    return v
50end
51
52local texblobs = setmetatableindex(newcategory)
53
54local function blob_raw_reset(category)
55    -- we need to keep the allblobs
56    if category then
57        if trace then
58            report("reset category %a",category)
59        end
60        texblobs[category] = nil
61    else
62        if trace then
63            report("reset all")
64        end
65        texblobs = setmetatableindex(newcategory)
66    end
67end
68
69local function blob_raw_dimensions(i)
70    local blob = allblobs[i]
71    if blob then
72        return getwhd(blob)
73    else
74        return 0, 0, 0
75    end
76end
77
78local function blob_raw_content(i)
79    return allblobs[i]
80end
81
82local function blob_raw_toutf(i)
83    return toutf(allblobs[i])
84end
85
86local function blob_raw_wipe(i)
87    allblobs[i] = false
88end
89
90mp.mf_blob_raw_dimensions = blob_raw_dimensions
91mp.mf_blob_raw_content    = blob_raw_content
92mp.mf_blob_raw_reset      = blob_raw_reset
93mp.mf_blob_raw_wipe       = blob_raw_wipe
94mp.mf_blob_raw_toutf      = blob_raw_toutf
95
96function mp.mf_blob_new(category,text)
97    if trace then
98        report("category %a, text %a",category,text)
99    end
100    texblobs[category].text = text
101end
102
103function mp.mf_blob_add(category,blob)
104    local tb = texblobs[category].blobs
105    local tn = #allblobs + 1
106    blob = hpack(blob)
107    allblobs[tn] = blob
108    tb[#tb+1] = tn
109    if trace then
110        report("category %a, blob %a set, content %a",category,tn,blob_raw_toutf(tn))
111    end
112end
113
114function mp.mf_blob_width(category,i)
115    local index = texblobs[category].blobs[i]
116    local blob  = allblobs[index]
117    if blob then
118        mppoints(getwidth(blob) or 0)
119    else
120        mpinteger(0)
121    end
122end
123
124function mp.mf_blob_size(category,i)
125    mpprint(#texblobs[category].blobs or 0)
126end
127
128function mp.mf_blob_index(category,i)
129    mpprint(texblobs[category].blobs[i] or 0)
130end
131
132function mp.mf_blob_dimensions(category,i)
133    local index = texblobs[category].blobs[i]
134    local blob  = allblobs[index]
135    if blob then
136        mptripletpoints(getwhd(blob))
137    else
138        mptriplet(0,0,0)
139    end
140end
141
142local sxsy = metapost.sxsy
143local cm   = metapost.cm
144
145local f_f  = formatters["%.6N"]
146
147local function injectblob(object,blob)
148    local sx, rx, ry, sy, tx, ty = cm(object)
149    local wd, ht, dp = blob_raw_dimensions(blob)
150    if wd then
151        object.path    = false
152        object.color   = false
153        object.grouped = true
154        object.istext  = true
155        return function()
156            if trace then
157                report("injecting blob %a, width %p, heigth %p, depth %p, text %a",blob,wd,ht,dp,blob_raw_toutf(blob))
158            end
159            context.MPLIBgetblobscaledcm(blob,
160                f_f(sx), f_f(rx), f_f(ry),
161                f_f(sy), f_f(tx), f_f(ty),
162                sxsy(wd,ht,dp))
163        end
164    end
165end
166
167-- mp.mf_blob_inject = injectblob
168
169local function getblob(box,blob)
170    setbox(box,blob_raw_content(blob))
171    blob_raw_wipe(blob)
172end
173
174interfaces.implement {
175    name      = "mpgetblob",
176    actions   = getblob,
177    arguments = { "integer", "integer" },
178}
179
180-- the plug:
181
182
183local function reset()
184    blob_raw_reset()
185end
186
187local function process(object,prescript,before,after)
188--     if prescript.tb_stage == "inject" then
189        local tb_blob = tonumber(prescript.tb_blob)
190        if tb_blob then
191            before[#before+1] = injectblob(object,tb_blob)
192        end
193--     end
194end
195
196metapost.installplugin {
197    name    = "texblob",
198    reset   = reset,
199    process = process,
200}
201
202-- Here follows an example of usage of the above: a more modern
203-- version of followtokens (in meta-imp-txt.mkiv).
204
205local nodecodes       = nodes.nodecodes
206local kerncodes       = nodes.kerncodes
207
208local glue_code       = nodecodes.glue
209local kern_code       = nodecodes.kern
210
211local fontkern_code   = kerncodes.fontkern
212local italickern_code = kerncodes.italickern
213
214local a_fontkern      = attributes.private("fontkern")
215
216local nuts            = nodes.nuts
217local takebox         = nuts.takebox
218local getlist         = nuts.getlist
219local getid           = nuts.getid
220local getsubtype      = nuts.getsubtype
221local setlink         = nuts.setlink
222local setlist         = nuts.setlist
223local getnext         = nuts.getnext
224local flatten_list    = nuts.flattendiscretionaries
225local remove_node     = nuts.remove
226local flushnode       = nuts.flush
227
228local addblob         = mp.mf_blob_add
229local newblob         = mp.mf_blob_new
230
231local visible_codes = {
232    [nodecodes.glyph] = true,
233    [nodecodes.glue]  = true,
234    [nodecodes.hlist] = true,
235    [nodecodes.vlist] = true,
236    [nodecodes.rule]  = true,
237}
238
239local function initialize(category,box)
240    local wrap = takebox(box)
241    if wrap then
242        local head = getlist(wrap)
243        local tail = nil
244        local temp = nil
245        if head then
246            local n = { }
247            local s = 0
248            head = flatten_list(head)
249            local current = head
250            while current do
251                local id = getid(current)
252                if visible_codes[id] then
253                    head, current, tail = remove_node(head,current)
254                    s = s + 1
255                    n[s] = tail
256                elseif id == kern_code then
257                    local subtype = getsubtype(current)
258                    if subtype == fontkern_code or subtype == italickern_code then -- or current[a_fontkern]
259                        head, current, temp = remove_node(head,current)
260                        setlink(tail,temp)
261                    else
262                        head, current, temp = remove_node(head,current)
263                        s = s + 1
264                        n[s] = temp
265                    end
266                elseif id == glue_code then
267                    head, current, temp = remove_node(head,current)
268                    s = s + 1
269                    n[s] = temp
270                else
271                    current = getnext(current)
272                end
273            end
274            for i=1,s do
275                n[i] = addblob(category,n[i])
276            end
277            setlist(wrap,head)
278        end
279        flushnode(wrap)
280    end
281end
282
283interfaces.implement {
284    name      = "MPLIBconvertfollowtext",
285    arguments = { "integer","integer" },
286    actions   = initialize,
287}
288
289local mp_category = 0
290local mp_str      = ""
291
292function mp.mf_inject_blob(category,str)
293    newblob(category,str) -- only for tracing
294    mp_category = category
295    mp_str      = str
296    tex.runlocal("mpblobtext")
297end
298
299interfaces.implement {
300    name    = "mpblobtext",
301    actions = function()
302        context.MPLIBfollowtext(mp_category,mp_str)
303    end
304}
305
306local process = function(object,prescript,before,after)
307    if prescript.ft_category then
308        object.path    = false
309        object.color   = false
310        object.grouped = true
311        object.istext  = true
312    end
313end
314
315metapost.installplugin {
316    name    = "followtext",
317    process = process,
318}
319