1if not modules then modules = { } end modules ['typo-drp'] = {
2 version = 1.001,
3 comment = "companion to typo-drp.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
10
11
12
13
14local tonumber, type, next = tonumber, type, next
15local ceil = math.ceil
16local settings_to_hash = utilities.parsers.settings_to_hash
17
18local trace_initials = false trackers.register("typesetters.initials", function(v) trace_initials = v end)
19local report_initials = logs.reporter("nodes","initials")
20
21local initials = typesetters.paragraphs or { }
22typesetters.initials = initials or { }
23
24local nodes = nodes
25
26local tasks = nodes.tasks
27local enableaction = tasks.enableaction
28local disableaction = tasks.disableaction
29
30local nuts = nodes.nuts
31local tonut = nodes.tonut
32
33local getnext = nuts.getnext
34local getprev = nuts.getprev
35local getchar = nuts.getchar
36local getid = nuts.getid
37local getattr = nuts.getattr
38local getwhd = nuts.getwhd
39
40local getprop = nuts.getprop
41local setprop = nuts.setprop
42
43local setattr = nuts.setattr
44local setlink = nuts.setlink
45local setprev = nuts.setprev
46local setnext = nuts.setnext
47local setfont = nuts.setfont
48local setchar = nuts.setchar
49local setwhd = nuts.setwhd
50local setkern = nuts.setkern
51local setoffsets = nuts.setoffsets
52local setglyphdata = nuts.setglyphdata
53local setattr = nuts.setattr
54
55local hpack_nodes = nuts.hpack
56
57local nodecodes = nodes.nodecodes
58
59local nodepool = nuts.pool
60local new_kern = nodepool.kern
61
62local insertbefore = nuts.insertbefore
63local insertafter = nuts.insertafter
64local remove_node = nuts.remove
65
66local startofpar = nuts.startofpar
67
68local nextnode = nuts.traversers.node
69local nextglyph = nuts.traversers.glyph
70
71local variables = interfaces.variables
72local v_default = variables.default
73local v_margin = variables.margin
74local v_auto = variables.auto
75local v_first = variables.first
76local v_keep = variables.keep
77local v_last = variables.last
78
79local texget = tex.get
80local texset = tex.set
81local unsetvalue = attributes.unsetvalue
82
83local glyph_code = nodecodes.glyph
84local hlist_code = nodecodes.hlist
85local glue_code = nodecodes.glue
86local kern_code = nodecodes.kern
87local par_code = nodecodes.par
88
89local actions = { }
90initials.actions = actions
91
92local a_initial = attributes.private("initial")
93local a_color = attributes.private('color')
94local a_transparency = attributes.private('transparency')
95local a_colormodel = attributes.private('colormodel')
96
97local category = characters.category
98
99local function set(par,specification)
100 enableaction("processors","typesetters.initials.handler")
101 if trace_initials then
102 report_initials("enabling initials")
103 end
104 setprop(par,a_initial,specification)
105end
106
107function initials.set(specification)
108 nuts.setparproperty(set,specification)
109end
110
111interfaces.implement {
112 name = "setinitial",
113 actions = initials.set,
114 arguments = {
115 {
116 { "location" },
117 { "enabled", "boolean" },
118 { "method" },
119 { "distance" ,"dimen" },
120 { "hoffset" ,"dimen" },
121 { "voffset" ,"dimen" },
122 { "font", "integer" },
123 { "dynamic", "integer" },
124 { "ca", "integer" },
125 { "ma", "integer" },
126 { "ta", "integer" },
127 { "n", "integer" },
128 { "m", "integer" },
129 }
130 }
131}
132
133
134
135
136actions[v_default] = function(head,setting)
137 local skip = false
138
139 local first = getnext(head)
140 local indent = false
141
142 if first and getid(first) == hlist_code then
143 first = getnext(first)
144 indent = true
145 end
146
147 while first and getid(first) ~= glyph_code do
148 first = getnext(first)
149 end
150 if first and getid(first) == glyph_code then
151 local ma = setting.ma or 0
152 local ca = setting.ca
153 local ta = setting.ta
154 local last = first
155 local distance = setting.distance or 0
156 local voffset = setting.voffset or 0
157 local hoffset = setting.hoffset or 0
158 local parindent = texget("parindent")
159 local baseline = texget("baselineskip",false)
160 local lines = tonumber(setting.n) or 0
161 local dynamic = setting.dynamic
162 local font = setting.font
163 local method = settings_to_hash(setting.method)
164 local length = tonumber(setting.m) or 1
165
166
167
168 if getattr(first,a_initial) then
169 for current in nextnode, getnext(first) do
170 if getattr(current,a_initial) then
171 last = current
172 else
173 break
174 end
175 end
176 elseif method[v_auto] then
177 local char = getchar(first)
178 local kind = category(char)
179 if kind == "po" or kind == "pi" then
180 if method[v_first] then
181
182 local next = getnext(first)
183 if not next then
184
185 return head
186 end
187 last = nil
188 for current in nextglyph, next do
189 head, first = remove_node(head,first,true)
190 first = current
191 last = first
192 break
193 end
194 if not last then
195
196 return head
197 end
198 else
199
200 local next = getnext(first)
201 if next and method[v_keep] then
202 skip = first
203 end
204 if not next then
205
206 return head
207 end
208 for current in nextglyph, next do
209 last = current
210 break
211 end
212 if last == first then
213 return head
214 end
215 end
216 elseif kind == "pf" then
217
218 else
219
220 end
221
222 local next = getnext(first)
223 if next then
224 for current, char in nextglyph, next do
225 local kind = category(char)
226 if kind == "po" then
227 if method[v_last] then
228
229 remove_node(head,current,true)
230 else
231
232 last = current
233 end
234 end
235 break
236 end
237 end
238 else
239 for current in nextglyph, first do
240 last = current
241 if length <= 1 then
242 break
243 else
244 length = length - 1
245 end
246 end
247 end
248 local current = first
249 while true do
250 local id = getid(current)
251 if id == kern_code then
252 setkern(current,0)
253 elseif id == glyph_code and skip ~= current then
254 local next = getnext(current)
255 if font then
256 setfont(current,font)
257 end
258 if dynamic > 0 then
259 setglyphdata(current,dynamic)
260 end
261
262 if ca and ca > 0 then
263 setattr(current,a_colormodel,ma == 0 and 1 or ma)
264 setattr(current,a_color,ca)
265 end
266 if ta and ta > 0 then
267 setattr(current,a_transparency,ta)
268 end
269
270 end
271 if current == last then
272 break
273 else
274 current = getnext(current)
275 end
276 end
277
278
279
280 local prev = getprev(first)
281 local next = getnext(last)
282
283 setprev(first)
284 setnext(last)
285 local dropper = hpack_nodes(first)
286 local width, height, depth = getwhd(dropper)
287 setwhd(dropper,0,0,0)
288
289 setlink(prev,dropper)
290 setlink(dropper,next)
291
292 if next then
293 local current = next
294 while current do
295 local id = getid(current)
296 if id == glue_code or id == kern_code then
297 local next = getnext(current)
298
299 remove_node(head,current,true)
300 current = next
301 else
302 break
303 end
304 end
305 end
306
307 local hoffset = width + hoffset + distance + (indent and parindent or 0)
308 for current in nextglyph, first do
309 if skip == current then
310 setoffsets(current,-hoffset,0)
311 else
312 setoffsets(current,-hoffset,-voffset)
313 end
314 if current == last then
315 break
316 end
317 end
318
319 first = dropper
320
321 if setting.location == v_margin then
322
323 else
324 if lines == 0 then
325 lines = ceil((height+voffset) / baseline)
326 end
327
328
329 local hangafter = - lines
330 local hangindent = width + distance
331 if trace_initials then
332 report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)
333 end
334 texset("hangafter",hangafter)
335 texset("hangindent",hangindent)
336 end
337 if indent then
338 insertafter(first,first,new_kern(-parindent))
339 end
340 end
341 return head
342end
343
344
345
346function initials.handler(head)
347 if getid(head) == par_code and startofpar(head) then
348 local settings = getprop(head,a_initial)
349 if settings then
350 disableaction("processors","typesetters.initials.handler")
351 local alternative = settings.alternative or v_default
352 local action = actions[alternative] or actions[v_default]
353 if action then
354 if trace_initials then
355 report_initials("processing initials, alternative %a",alternative)
356 end
357 return action(head,settings)
358 end
359 end
360 end
361 return head
362end
363 |