OSDN Git Service

Another approach for #3: cancel profiling in OTR
[luatex-ja/luatexja.git] / src / ltj-lineskip.lua
1 --
2 -- ltj-lineskip.lua
3 --
4 luatexja.load_module 'base'; local ltjb = luatexja.base
5 luatexja.load_module 'direction'; local ltjd = luatexja.direction
6 luatexja.lineskip = luatexja.lineskip or {}
7
8 local to_direct = node.direct.todirect
9 local to_node = node.direct.tonode
10 local ltjl = luatexja.lineskip
11 local id_glue    = node.id 'glue'
12 local id_penalty = node.id 'penalty'
13 local id_hlist   = node.id 'hlist'
14 local getlist = node.direct.getlist
15 local node_new = node.direct.new
16 local node_prev = node.direct.getprev
17 local node_next = node.direct.getnext
18 local getid = node.direct.getid
19 local getsubtype = node.direct.getsubtype
20 local getdepth = node.direct.getdepth
21 local getheight = node.direct.getheight
22 local texget = tex.get
23
24 local node_getglue = node.getglue
25 local setglue = node.direct.setglue
26 local setsubtype = node.direct.setsubtype
27 local function copy_glue (new_glue, old_glue_name, subtype, new_w)
28    setsubtype(new_glue, subtype)
29    local w,st,sp,sto,spo = texget(old_glue_name, true)
30    setglue(new_glue, new_w or w, st, sp, sto, spo)
31 end
32 ltjl.copy_glue = copy_glue
33
34 function ltjl.p_dummy(before, after)
35    return nil, 0
36 end
37 function ltjl.l_dummy(dist, g, adj, normal, bw, loc)
38    if dist < tex.lineskiplimit then
39       copy_glue(g, 'lineskip', 1, texget('lineskip', false) + adj)
40    else
41       copy_glue(g, 'baselineskip', 2, normal)
42    end
43 end
44
45 local ltj_profiler, ltj_skip = ltjl.p_dummy, ltjl.l_dummy
46 function ltjl.setting(profiler, skip_method)
47    ltj_profiler = ltjl['p_'..tostring(profiler)] or ltjl.p_dummy
48    ltj_skip = ltjl['l_'..tostring(skip_method)] or ltjl.l_dummy
49 end
50
51 do
52     local backup
53     function ltjl.setting_backup()
54         backup = { ltj_profiler, ltj_skip }
55         ltj_profiler, ltj_skip = ltjl.p_dummy, ltjl.l_dummy
56     end
57     function ltjl.setting_restore()
58         if backup then
59             ltj_profiler, ltj_skip, backup = backup[1], backup[2], nil
60         end
61     end
62 end
63
64 do
65 local traverse_id = node.direct.traverse_id
66 local function adjust_glue(nh)
67    local h = to_direct(nh)
68    local bw = texget('baselineskip',false)
69    for x in traverse_id(id_glue, h) do
70      local xs = getsubtype(x)
71      if (xs==1) or (xs==2) then
72         local p, n = node_prev(x), node_next(x)
73         if p then
74         local pid = getid(p)
75            while (id_glue<=pid) and (pid<=id_penalty) and node_prev(p) do
76              p = node_prev(p); pid = getid(p)
77            end
78            if pid==id_hlist and getid(n)==id_hlist then
79              local normal = bw - getdepth(p) - getheight(n)
80              local lmin, adj = ltj_profiler(p, n, false, bw)
81              ltj_skip(lmin or normal, x, adj, normal, bw)
82            end
83         end
84      end
85    end
86    return true
87 end
88 ltjb.add_to_callback('post_linebreak_filter', adjust_glue, 'ltj.lineskip', 10000)
89 end
90
91 do
92 local p_dummy = ltjl.p_dummy
93 local make_dir_whatsit = luatexja.direction.make_dir_whatsit
94 local get_dir_count = luatexja.direction.get_dir_count
95 local getwhd = node.direct.getwhd
96 local setnext = node.direct.setnext
97 local getnest = tex.getnest
98
99 local function dir_adjust_append_vlist(b, loc, prev, mirrored)
100    local old_b = to_direct(b)
101    local new_b = loc=='box' and
102       make_dir_whatsit(old_b, old_b, get_dir_count(), 'append_vlist') or old_b
103    local _, ht, dp = getwhd(new_b)
104    if prev > -65536000 then
105       local bw = texget('baselineskip', false)
106       local normal = bw - prev - (mirrored and dp or ht)
107       local lmin, adj = nil, 0
108       local tail = to_direct(getnest().tail)
109       if p_dummy~=ltj_profiler then
110          while tail and (id_glue<=getid(tail)) and (getid(tail)<=id_penalty) do
111             tail = node_prev(tail)
112          end
113       end
114       if tail then
115          if getid(tail)==id_hlist and getid(new_b)==id_hlist then
116             if getdepth(tail)==prev then
117                lmin, adj = ltj_profiler(tail, new_b, mirrored, bw)
118             end
119          end
120       end
121       local g = node_new(id_glue)
122       ltj_skip(lmin or normal, g, adj, normal, bw, loc)
123       setnext(g, new_b); return to_node(g), (mirrored and ht or dp)
124    else return to_node(new_b), (mirrored and ht or dp)
125    end
126 end
127 ltjb.add_to_callback('append_to_vlist_filter', dir_adjust_append_vlist, 'ltj.lineskip', 10000)
128 end
129