1if not modules then modules = { } end modules [ ' back-shp ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to lpdf-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 type , next = type , next
10local round = math . round
11
12local setmetatableindex = table . setmetatableindex
13local formatters = string . formatters
14local concat = table . concat
15local keys = table . keys
16local sortedhash = table . sortedhash
17local splitstring = string . split
18local idiv = number . idiv
19local extract = bit32 . extract
20local nuts = nodes . nuts
21
22local tonut = nodes . tonut
23local tonode = nodes . tonode
24
25local getdirection = nuts . getdirection
26local getlist = nuts . getlist
27local getoffsets = nuts . getoffsets
28local getorientation = nuts . getorientation
29local getfield = nuts . getfield
30local getwhd = nuts . getwhd
31local getkern = nuts . getkern
32local getheight = nuts . getheight
33local getdepth = nuts . getdepth
34local getwidth = nuts . getwidth
35local getnext = nuts . getnext
36local getsubtype = nuts . getsubtype
37local getid = nuts . getid
38local getleader = nuts . getleader
39local getglue = nuts . getglue
40local getshift = nuts . getshift
41local getdata = nuts . getdata
42local getboxglue = nuts . getboxglue
43local getexpansion = nuts . getexpansion
44
45local setdirection = nuts . setdirection
46local setfield = nuts . setfield
47local setlink = nuts . setlink
48
49local isglyph = nuts . isglyph
50local findtail = nuts . tail
51local nextdir = nuts . traversers . dir
52local nextnode = nuts . traversers . node
53
54local rangedimensions = nuts . rangedimensions
55local effectiveglue = nuts . effective_glue
56
57local nodecodes = nodes . nodecodes
58local whatsitcodes = nodes . whatsitcodes
59local leadercodes = nodes . leadercodes
60local subtypes = nodes . subtypes
61
62local dircodes = nodes . dircodes
63local normaldir_code = dircodes . normal
64
65local dirvalues = nodes . dirvalues
66local lefttoright_code = dirvalues . lefttoright
67local righttoleft_code = dirvalues . righttoleft
68
69local glyph_code = nodecodes . glyph
70local kern_code = nodecodes . kern
71local glue_code = nodecodes . glue
72local hlist_code = nodecodes . hlist
73local vlist_code = nodecodes . vlist
74local dir_code = nodecodes . dir
75local disc_code = nodecodes . disc
76local math_code = nodecodes . math
77local rule_code = nodecodes . rule
78local marginkern_code = nodecodes . marginkern
79local whatsit_code = nodecodes . whatsit
80
81local leader_code = leadercodes . leader
82local cleader_code = leadercodes . cleader
83local xleader_code = leadercodes . xleader
84local gleader_code = leadercodes . gleader
85
86local saveposwhatsit_code = whatsitcodes . savepos
87local userdefinedwhatsit_code = whatsitcodes . userdefined
88local openwhatsit_code = whatsitcodes . open
89local writewhatsit_code = whatsitcodes . write
90local closewhatsit_code = whatsitcodes . close
91local lateluawhatsit_code = whatsitcodes . latelua
92local literalwhatsit_code = whatsitcodes . literal
93local setmatrixwhatsit_code = whatsitcodes . setmatrix
94local savewhatsit_code = whatsitcodes . save
95local restorewhatsit_code = whatsitcodes . restore
96
97local texget = tex . get
98
99local fontdata = fonts . hashes . identifiers
100local characters = fonts . hashes . characters
101local parameters = fonts . hashes . parameters
102
103local trace_missing = false
104
105local report = logs . reporter ( " drivers " )
106local report_missing = logs . reporter ( " drivers " , " missing " )
107
108
109local getpagedimensions getpagedimensions = function ( )
110 getpagedimensions = backends . codeinjections . getpagedimensions
111 return getpagedimensions ( )
112end
113
114local instances = { }
115
116drivers = {
117 instances = instances ,
118 lmtxversion = 0 . 10 ,
119}
120
121local defaulthandlers = {
122
123 prepare = function ( ) end ,
124 initialize = function ( ) end ,
125 finalize = function ( ) end ,
126 updatefontstate = function ( ) end ,
127 wrapup = function ( ) end ,
128
129 pushorientation = function ( ) if trace_missing then report ( " pushorientation " ) end end ,
130 poporientation = function ( ) if trace_missing then report ( " poporientation " ) end end ,
131 flushcharacter = function ( ) if trace_missing then report ( " flushcharacter " ) end end ,
132 flushrule = function ( ) if trace_missing then report ( " flushrule " ) end end ,
133 flushlatelua = function ( ) if trace_missing then report ( " flushlatelua " ) end end ,
134 flushpdfliteral = function ( ) if trace_missing then report ( " flushpdfliteral " ) end end ,
135 flushpdfsetmatrix = function ( ) if trace_missing then report ( " flushpdfsetmatrix " ) end end ,
136 flushpdfsave = function ( ) if trace_missing then report ( " flushpdfsave " ) end end ,
137 flushpdfrestore = function ( ) if trace_missing then report ( " flushpdfrestore " ) end end ,
138 flushspecial = function ( ) if trace_missing then report ( " flushspecial " ) end end ,
139 flushpdfimage = function ( ) if trace_missing then report ( " flushpdfimage " ) end end ,
140}
141
142function drivers . install ( specification )
143 local name = specification . name
144 if not name then
145 report ( " missing driver name " )
146 return
147 end
148 local actions = specification . actions
149 if not actions then
150 report ( " no actions for driver %a " , name )
151 return
152 end
153 local flushers = specification . flushers
154 if not flushers then
155 report ( " no flushers for driver %a " , name )
156 return
157 end
158 setmetatableindex ( flushers , defaulthandlers )
159 instances [ name ] = specification
160end
161
162function drivers . prepare ( name )
163 local driver = instances [ name ]
164 if not driver then
165 return
166 end
167 local prepare = driver . actions . prepare
168 if prepare then
169 prepare ( )
170 end
171end
172
173function drivers . wrapup ( name )
174 local driver = instances [ name ]
175 if not driver then
176 return
177 end
178 local wrapup = driver . actions . wrapup
179 if wrapup then
180 wrapup ( )
181 end
182end
183
184
185
186local synctex = false
187
188local lastfont = nil
189local fontcharacters = nil
190
191local magicconstants = tex . magicconstants
192local trueinch = magicconstants . trueinch
193local maxdimen = magicconstants . maxdimen
194local running = magicconstants . running
195
196local pos_h = 0
197local pos_v = 0
198local pos_r = lefttoright_code
199local shippingmode = " none "
200
201local abs_max_v = 0
202local abs_max_h = 0
203
204local shipbox_h = 0
205local shipbox_v = 0
206local page_size_h = 0
207local page_size_v = 0
208
209
210
211local initialize
212local finalize
213local updatefontstate
214local pushorientation
215local poporientation
216local flushcharacter
217local flushrule
218local flushpdfliteral
219local flushpdfsetmatrix
220local flushpdfsave
221local flushpdfrestore
222local flushlatelua
223local flushspecial
224local flushpdfimage
225
226
227
228function drivers . getpos ( ) return round ( pos_h ) , round ( pos_v ) end
229function drivers . gethpos ( ) return round ( pos_h ) end
230function drivers . getvpos ( ) return round ( pos_v ) end
231
232local function synch_pos_with_cur ( ref_h , ref_v , h , v )
233 if pos_r = = righttoleft_code then
234 pos_h = ref_h - h
235 else
236 pos_h = ref_h + h
237 end
238 pos_v = ref_v - v
239end
240
241
242
243local flush_character
244
245local stack = setmetatableindex ( " table " )
246local level = 0
247local nesting = 0
248local main = 0
249
250
251
252local function flush_vf_packet ( pos_h , pos_v , pos_r , font , char , data , factor , vfcommands )
253
254 if nesting > 100 then
255 return
256 elseif nesting = = 0 then
257 main = font
258 end
259
260 nesting = nesting + 1
261
262 local saved_h = pos_h
263 local saved_v = pos_v
264 local saved_r = pos_r
265 pos_r = lefttoright_code
266
267 local data = fontdata [ font ]
268 local fnt = font
269 local fonts = data . fonts
270 local siz = ( data . parameters . factor or 1 ) / 65536
271
272 local function flushchar ( font , char , fnt , chr , f , e )
273 if fnt then
274 local nest = char ~ = chr or font ~ = fnt
275 if fnt = = 0 then
276 fnt = main
277 end
278 return flush_character ( false , fnt , chr , factor , nest , pos_h , pos_v , pos_r , f , e )
279 else
280 return 0
281 end
282 end
283
284
285
286 for i = 1 , # vfcommands do
287 local packet = vfcommands [ i ]
288 local command = packet [ 1 ]
289 if command = = " char " then
290 local chr , f , e = packet [ 2 ] , packet [ 3 ] , packet [ 4 ]
291 pos_h = pos_h + flushchar ( font , char , fnt , chr , f , e )
292 elseif command = = " slot " then
293 local index , chr , f , e = packet [ 2 ] , packet [ 3 ] , packet [ 4 ] , packet [ 5 ]
294 if index = = 0 then
295 pos_h = pos_h + flushchar ( font , char , font , chr , f , e )
296 else
297 local okay = fonts and fonts [ index ]
298 if okay then
299 local fnt = okay . id
300 if fnt then
301 pos_h = pos_h + flushchar ( font , char , fnt , chr , f , e )
302 end
303 end
304 end
305 elseif command = = " right " then
306 local h = packet [ 2 ]
307 if factor ~ = 0 and h ~ = 0 then
308 h = h + h * factor / 1000
309 end
310 pos_h = pos_h + h
311 elseif command = = " down " then
312 local v = packet [ 2 ]
313 pos_v = pos_v - v
314 elseif command = = " push " then
315 level = level + 1
316 local s = stack [ level ]
317 s [ 1 ] = pos_h
318 s [ 2 ] = pos_v
319 elseif command = = " pop " then
320 if level > 0 then
321 local s = stack [ level ]
322 pos_h = s [ 1 ]
323 pos_v = s [ 2 ]
324 level = level - 1
325 end
326 elseif command = = " pdf " then
327 flushpdfliteral ( false , pos_h , pos_v , packet [ 2 ] , packet [ 3 ] )
328 elseif command = = " rule " then
329 local size_v = packet [ 2 ]
330 local size_h = packet [ 3 ]
331 if factor ~ = 0 and size_h > 0 then
332 size_h = size_h + size_h * factor / 1000
333 end
334 if size_h > 0 and size_v > 0 then
335 flushsimplerule ( pos_h , pos_v , pos_r , size_h , size_v )
336 pos_h = pos_h + size_h
337 end
338 elseif command = = " font " then
339 local index = packet [ 2 ]
340 local okay = fonts and fonts [ index ]
341 if okay then
342 fnt = okay . id or fnt
343 end
344 elseif command = = " lua " then
345 local code = packet [ 2 ]
346 if type ( code ) ~ = " function " then
347 code = loadstring ( code )
348 end
349 if type ( code ) = = " function " then
350 code ( font , char , pos_h , pos_v )
351 end
352 elseif command = = " node " then
353 hlist_out ( packet [ 2 ] )
354 elseif command = = " image " then
355
356
357 local image = packet [ 2 ]
358
359 elseif command = = " pdfmode " then
360
361
362
363
364
365
366
367 end
368 end
369
370 pos_h = saved_h
371 pos_v = saved_v
372 pos_r = saved_r
373
374
375 nesting = nesting - 1
376end
377
378flush_character = function ( current , font , char , factor , vfcommands , pos_h , pos_v , pos_r , f , e )
379
380 if font ~ = lastfont then
381 lastfont = font
382 fontcharacters = characters [ font ]
383 updatefontstate ( font )
384 end
385
386 local data = fontcharacters [ char ]
387 if not data then
388
389
390 return 0 , 0 , 0
391 end
392 local width , height , depth
393 if current then
394 width , height , depth = getwhd ( current )
395 factor = getexpansion ( current )
396 if factor and factor ~ = 0 then
397 width = ( 1 . 0 + factor / 1000000 . 0 ) * width
398 end
399 else
400 width = data . width or 0
401 height = data . height or 0
402 depth = data . depth or 0
403 if not factor then
404 factor = 0
405 end
406 end
407 if pos_r = = righttoleft_code then
408 pos_h = pos_h - width
409 end
410 if vfcommands then
411 vfcommands = data . commands
412 end
413 if vfcommands then
414 flush_vf_packet ( pos_h , pos_v , pos_r , font , char , data , factor , vfcommands )
415 else
416 local orientation = data . orientation
417 if orientation and ( orientation = = 1 or orientation = = 3 ) then
418 local x , y = data . xoffset , data . yoffset
419 if x then
420 pos_h = pos_h + x
421 end
422 if y then
423 pos_v = pos_v + y
424 end
425 pushorientation ( orientation , pos_h , pos_v )
426 flushcharacter ( current , pos_h , pos_v , pos_r , font , char , data , factor , width , f , e )
427 poporientation ( orientation , pos_h , pos_v )
428 else
429 flushcharacter ( current , pos_h , pos_v , pos_r , font , char , data , factor , width , f , e )
430 end
431 end
432 return width , height , depth
433end
434
435
436
437local function reset_state ( )
438 pos_h = 0
439 pos_v = 0
440 pos_r = lefttoright_code
441 shipbox_h = 0
442 shipbox_v = 0
443 shippingmode = " none "
444 page_size_h = 0
445 page_size_v = 0
446
447
448end
449
450local function dirstackentry ( t , k )
451 local v = {
452 cur_h = 0 ,
453 cur_v = 0 ,
454 ref_h = 0 ,
455 ref_v = 0 ,
456 }
457 t [ k ] = v
458 return v
459end
460
461local dirstack = setmetatableindex ( dirstackentry )
462
463local function reset_dir_stack ( )
464 dirstack = setmetatableindex ( dirstackentry )
465end
466
467local function open_write_file ( n )
468
469
470
471
472
473
474
475
476
477
478
479
480
481end
482
483local function close_write_file ( n )
484
485end
486
487local function write_to_file ( current )
488 local stream = getfield ( current , " stream " )
489 local data = getdata ( current )
490 texio . write_nl ( stream , data )
491end
492
493local function wrapup_leader ( current , subtype )
494 if subtype = = writewhatsit_code then
495 write_to_file ( current )
496 elseif subtype = = closewhatsit_code then
497 close_write_file ( current )
498 elseif subtype = = openwhatsit_code then
499 open_write_file ( current )
500 end
501end
502
503local hlist_out , vlist_out do
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533 local function applyanchor ( orientation , x , y , width , height , depth , woffset , hoffset , doffset , xoffset , yoffset )
534 local ot = extract ( orientation , 0 , 4 )
535 local ay = extract ( orientation , 4 , 4 )
536 local ax = extract ( orientation , 8 , 4 )
537 local of = extract ( orientation , 12 , 4 )
538 if ot = = 4 then
539 ot , ay = 0 , 1
540 elseif ot = = 5 then
541 ot , ay = 0 , 2
542 end
543 if ot = = 0 or ot = = 2 then
544 if ax = = 1 then x = x - width
545 elseif ax = = 2 then x = x + width
546 elseif ax = = 3 then x = x - width / 2
547 elseif ax = = 4 then x = x + width / 2
548 end
549 if ot = = 2 then
550 doffset , hoffset = hoffset , doffset
551 end
552 if ay = = 1 then y = y - doffset
553 elseif ay = = 2 then y = y + hoffset
554 elseif ay = = 3 then y = y + ( doffset + hoffset ) / 2 - doffset
555 end
556 elseif ot = = 1 or ot = = 3 then
557 if ay = = 1 then y = y - height
558 elseif ay = = 2 then y = y + height
559 elseif ay = = 3 then y = y - height / 2
560 end
561 if ot = = 1 then
562 doffset , hoffset = hoffset , doffset
563 end
564 if ax = = 1 then x = x - width
565 elseif ax = = 2 then x = x + width
566 elseif ax = = 3 then x = x - width / 2
567 elseif ax = = 4 then x = x + width / 2
568 elseif ax = = 5 then x = x - hoffset
569 elseif ax = = 6 then x = x + doffset
570 end
571 end
572 return ot , x + xoffset , y - yoffset
573 end
574
575
576
577 rangedimensions = node . direct . naturalwidth or rangedimensions
578
579 local function calculate_width_to_enddir ( this_box , begindir )
580 local dir_nest = 1
581 local enddir = begindir
582 for current , subtype in nextdir , getnext ( begindir ) do
583 if subtype = = normaldir_code then
584 dir_nest = dir_nest + 1
585 else
586 dir_nest = dir_nest - 1
587 end
588 if dir_nest = = 0 then
589 enddir = current
590 local width = rangedimensions ( this_box , begindir , enddir )
591 return enddir , width
592 end
593 end
594 if enddir = = begindir then
595 local width = rangedimensions ( this_box , begindir )
596 return enddir , width
597 end
598 return enddir , 0
599 end
600
601
602
603 hlist_out = function ( this_box , current )
604 local outer_doing_leaders = false
605
606 local ref_h = pos_h
607 local ref_v = pos_v
608 local ref_r = pos_r
609 pos_r = getdirection ( this_box )
610
611 local boxwidth ,
612 boxheight ,
613 boxdepth = getwhd ( this_box )
614 local g_set ,
615 g_order ,
616 g_sign = getboxglue ( this_box )
617
618 local cur_h = 0
619 local cur_v = 0
620
621 if not current then
622 current = getlist ( this_box )
623 end
624
625
626
627
628
629 while current do
630 local char , id = isglyph ( current )
631 if char then
632 local x_offset , y_offset = getoffsets ( current )
633 if x_offset ~ = 0 or y_offset ~ = 0 then
634 synch_pos_with_cur ( ref_h , ref_v , cur_h + x_offset , cur_v - y_offset )
635 end
636 local wd , ht , dp = flush_character ( current , id , char , false , true , pos_h , pos_v , pos_r )
637 cur_h = cur_h + wd
638 elseif id = = glue_code then
639 local rule_wd , rule_ht , rule_dp
640 if g_sign = = 0 then
641 rule_wd = getwidth ( current )
642 else
643 rule_wd = effectiveglue ( current , this_box )
644 end
645 local leader = getleader ( current )
646 if leader then
647 local leader_wd = 0
648 local boxdir = getdirection ( leader ) or lefttoright_code
649 local width , height , depth = getwhd ( leader )
650 if getid ( leader ) = = rule_code then
651 rule_ht = height
652 rule_dp = depth
653 if rule_ht = = running then
654 rule_ht = boxheight
655 end
656 if rule_dp = = running then
657 rule_dp = boxdepth
658 end
659 local left , right = getoffsets ( leader )
660 if left ~ = 0 then
661 rule_ht = rule_ht - left
662 pos_v = pos_v + left
663 end
664 if right ~ = 0 then
665 rule_dp = rule_dp - right
666 end
667 local total = rule_ht + rule_dp
668 if total > 0 and rule_wd > 0 then
669 local size_h = rule_wd
670 local size_v = total
671 if pos_r = = righttoleft_code then
672 pos_h = pos_h - size_h
673 end
674 pos_v = pos_v - rule_dp
675 flushrule ( current , pos_h , pos_v , pos_r , size_h , size_v )
676 end
677 cur_h = cur_h + rule_wd
678 else
679 leader_wd = width
680 if leader_wd > 0 and rule_wd > 0 then
681 rule_wd = rule_wd + 10
682 local edge = cur_h + rule_wd
683 local lx = 0
684 local subtype = getsubtype ( current )
685 if subtype = = gleader_code then
686 local save_h = cur_h
687 if pos_r = = righttoleft_code then
688 cur_h = ref_h - shipbox_h - cur_h
689 cur_h = leader_wd * ( cur_h / leader_wd )
690 cur_h = ref_h - shipbox_h - cur_h
691 else
692 cur_h = cur_h + ref_h - shipbox_h
693 cur_h = leader_wd * ( cur_h / leader_wd )
694 cur_h = cur_h - ref_h - shipbox_h
695 end
696 if cur_h < save_h then
697 cur_h = cur_h + leader_wd
698 end
699 elseif subtype = = leader_code then
700 local save_h = cur_h
701 cur_h = leader_wd * ( cur_h / leader_wd )
702 if cur_h < save_h then
703 cur_h = cur_h + leader_wd
704 end
705 else
706 lq = rule_wd / leader_wd
707 lr = rule_wd % leader_wd
708 if subtype = = cleader_code then
709 cur_h = cur_h + lr / 2
710 else
711 lx = lr / ( lq + 1 )
712 cur_h = cur_h + ( lr - ( lq - 1 ) * lx ) / 2
713 end
714 end
715 while cur_h + leader_wd < = edge do
716 local basepoint_h = 0
717 local basepoint_v = getshift ( leader )
718 if boxdir ~ = pos_r then
719 basepoint_h = boxwidth
720 end
721 synch_pos_with_cur ( ref_h , ref_v , cur_h + basepoint_h , basepoint_v )
722 outer_doing_leaders = doing_leaders
723 doing_leaders = true
724 if getid ( leader ) = = vlist_code then
725 vlist_out ( leader )
726 else
727 hlist_out ( leader )
728 end
729 doing_leaders = outer_doing_leaders
730 cur_h = cur_h + leader_wd + lx
731 end
732 cur_h = edge - 10
733 else
734 cur_h = cur_h + rule_wd
735
736
737
738
739 end
740 end
741 else
742 cur_h = cur_h + rule_wd
743
744
745
746
747 end
748 elseif id = = hlist_code or id = = vlist_code then
749
750 local boxdir = getdirection ( current ) or lefttoright_code
751 local width , height , depth = getwhd ( current )
752 local list = getlist ( current )
753 if list then
754 local shift , orientation = getshift ( current )
755 if not orientation then
756 local basepoint_h = boxdir ~ = pos_r and width or 0
757
758 synch_pos_with_cur ( ref_h , ref_v , cur_h + basepoint_h , shift )
759 if id = = vlist_code then
760 vlist_out ( current , list )
761 else
762 hlist_out ( current , list )
763 end
764 elseif orientation = = 0x1000 then
765 local orientation , xoffset , yoffset = getorientation ( current )
766 local basepoint_h = boxdir ~ = pos_r and width or 0
767
768 synch_pos_with_cur ( ref_h , ref_v , cur_h + basepoint_h + xoffset , shift - yoffset )
769 if id = = vlist_code then
770 vlist_out ( current , list )
771 else
772 hlist_out ( current , list )
773 end
774 else
775 local orientation , xoffset , yoffset , woffset , hoffset , doffset = getorientation ( current )
776 local orientation , basepoint_h , basepoint_v = applyanchor ( orientation , 0 , shift , width , height , depth , woffset , hoffset , doffset , xoffset , yoffset )
777 if orientation = = 1 then
778 basepoint_h = basepoint_h + doffset
779 if boxdir = = pos_r then
780 basepoint_v = basepoint_v - height
781 end
782 elseif orientation = = 2 then
783 if boxdir = = pos_r then
784 basepoint_h = basepoint_h + width
785 end
786 elseif orientation = = 3 then
787 basepoint_h = basepoint_h + hoffset
788 if boxdir ~ = pos_r then
789 basepoint_v = basepoint_v - height
790 end
791 end
792 synch_pos_with_cur ( ref_h , ref_v , cur_h + basepoint_h , cur_v + basepoint_v )
793 pushorientation ( orientation , pos_h , pos_v , pos_r )
794 if id = = vlist_code then
795 vlist_out ( current , list )
796 else
797 hlist_out ( current , list )
798 end
799 poporientation ( orientation , pos_h , pos_v , pos_r )
800 end
801 else
802
803
804
805
806
807
808
809 end
810 cur_h = cur_h + width
811 elseif id = = disc_code then
812 local replace = getfield ( current , " replace " )
813 if replace and getsubtype ( current ) ~ = select_disc then
814
815 setlink ( findtail ( replace ) , getnext ( current ) )
816 setlink ( current , replace )
817 setfield ( current , " replace " )
818 end
819 elseif id = = kern_code then
820
821
822
823 local kern = getkern ( current )
824 local factor = getexpansion ( current )
825 if factor and factor ~ = 0 then
826 cur_h = cur_h + ( 1 . 0 + factor / 1000000 . 0 ) * kern
827 else
828 cur_h = cur_h + kern
829 end
830 elseif id = = rule_code then
831
832 local ruledir = getdirection ( current )
833 local width , height , depth = getwhd ( current )
834 local left , right = getoffsets ( current )
835 if not ruledir then
836 ruledir = pos_r
837 setdirection ( current , ruledir )
838 end
839 if height = = running then
840 height = boxheight
841 end
842 if depth = = running then
843 depth = boxdepth
844 end
845 if left ~ = 0 then
846 height = height - left
847 pos_v = pos_v + left
848 end
849 if right ~ = 0 then
850 depth = depth - right
851 end
852 local total = height + depth
853 if total > 0 and width > 0 then
854 local size_h = width
855 local size_v = total
856 if pos_r = = righttoleft_code then
857 pos_h = pos_h - size_h
858 end
859 pos_v = pos_v - depth
860 flushrule ( current , pos_h , pos_v , pos_r , size_h , size_v )
861 end
862 cur_h = cur_h + width
863 elseif id = = math_code then
864
865
866
867 local kern = getkern ( current )
868 if kern ~ = 0 then
869 cur_h = cur_h + kern
870 elseif g_sign = = 0 then
871 rule_wd = getwidth ( current )
872 else
873 rule_wd = effectiveglue ( current , this_box )
874 end
875 elseif id = = dir_code then
876
877
878
879
880 local dir , cancel = getdirection ( current )
881 if cancel then
882 local ds = dirstack [ current ]
883 ref_h = ds . ref_h
884 ref_v = ds . ref_v
885 cur_h = ds . cur_h
886 cur_v = ds . cur_v
887 pos_r = dir
888 else
889 local enddir , width = calculate_width_to_enddir ( this_box , current )
890 local ds = dirstack [ enddir ]
891 ds . cur_h = cur_h + width
892 if dir ~ = pos_r then
893 cur_h = ds . cur_h
894 end
895 if enddir ~ = current then
896 local ds = dirstack [ enddir ]
897 ds . cur_v = cur_v
898 ds . ref_h = ref_h
899 ds . ref_v = ref_v
900 setdirection ( enddir , pos_r )
901 end
902 synch_pos_with_cur ( ref_h , ref_v , cur_h , cur_v )
903 ref_h = pos_h
904 ref_v = pos_v
905 cur_h = 0
906 cur_v = 0
907 pos_r = dir
908 end
909 elseif id = = whatsit_code then
910 local subtype = getsubtype ( current )
911 if subtype = = literalwhatsit_code then
912 flushpdfliteral ( current , pos_h , pos_v )
913 elseif subtype = = lateluawhatsit_code then
914 flushlatelua ( current , pos_h , pos_v , cur_h , cur_v )
915 elseif subtype = = setmatrixwhatsit_code then
916 flushpdfsetmatrix ( current , pos_h , pos_v )
917 elseif subtype = = savewhatsit_code then
918 flushpdfsave ( current , pos_h , pos_v )
919 elseif subtype = = restorewhatsit_code then
920 flushpdfrestore ( current , pos_h , pos_v )
921
922
923 elseif subtype = = saveposwhatsit_code then
924 last_position_x = pos_h
925 last_position_y = pos_v
926 elseif subtype = = userdefinedwhatsit_code then
927
928 elseif subtype = = openwhatsit_code or subtype = = writewhatsit_code or subtype = = closewhatsit_code then
929 if not doing_leaders then
930 wrapup_leader ( current , subtype )
931 end
932 end
933 elseif id = = marginkern_code then
934 cur_h = cur_h + getkern ( current )
935 end
936 current = getnext ( current )
937 synch_pos_with_cur ( ref_h , ref_v , cur_h , cur_v )
938 end
939
940
941
942 pos_h = ref_h
943 pos_v = ref_v
944 pos_r = ref_r
945 end
946
947 vlist_out = function ( this_box , current )
948 local outer_doing_leaders = false
949
950 local ref_h = pos_h
951 local ref_v = pos_v
952 local ref_r = pos_r
953 pos_r = getdirection ( this_box )
954
955 local boxwidth ,
956 boxheight ,
957 boxdepth = getwhd ( this_box )
958 local g_set ,
959 g_order ,
960 g_sign = getboxglue ( this_box )
961
962 local cur_h = 0
963 local cur_v = - boxheight
964
965 local top_edge = cur_v
966
967 synch_pos_with_cur ( ref_h , ref_v , cur_h , cur_v )
968
969 if not current then
970 current = getlist ( this_box )
971 end
972
973
974
975
976
977
978
979 for current , id , subtype in nextnode , current do
980 if id = = glue_code then
981 local rule_wd , rule_ht , rule_dp
982 if g_sign = = 0 then
983 rule_ht = getwidth ( current )
984 else
985 rule_ht = effectiveglue ( current , this_box )
986 end
987 local leader = getleader ( current )
988 if leader then
989 local width , height , depth = getwhd ( leader )
990 if getid ( leader ) = = rule_code then
991 rule_wd = width
992 rule_dp = 0
993 if rule_wd = = running then
994 rule_wd = boxwidth
995 end
996 local left , right = getoffsets ( leader )
997 if left ~ = 0 then
998 rule_wd = rule_wd - left
999 cur_h = cur_h + left
1000 end
1001 if right ~ = 0 then
1002 rule_wd = rule_wd - right
1003 end
1004 local total = rule_ht + rule_dp
1005 if total > 0 and rule_wd > 0 then
1006 local size_h = rule_wd
1007 local size_v = total
1008 if pos_r = = righttoleft_code then
1009 cur_h = cur_h - size_h
1010 end
1011 cur_v = cur_v - size_v
1012 flushrule ( current , pos_h , pos_v - size_v , pos_r , size_h , size_v )
1013 end
1014 cur_v = cur_v + total
1015 else
1016 local leader_ht = height + depth
1017 if leader_ht > 0 and rule_ht > 0 then
1018 rule_ht = rule_ht + 10
1019 local edge = cur_v + rule_ht
1020 local ly = 0
1021
1022 if subtype = = gleader_code then
1023 save_v = cur_v
1024 cur_v = ref_v - shipbox_v - cur_v
1025 cur_v = leader_ht * ( cur_v / leader_ht )
1026 cur_v = ref_v - shipbox_v - cur_v
1027 if cur_v < save_v then
1028 cur_v = cur_v + leader_ht
1029 end
1030 elseif subtype = = leader_code then
1031 save_v = cur_v
1032 cur_v = top_edge + leader_ht * ( ( cur_v - top_edge ) / leader_ht )
1033 if cur_v < save_v then
1034 cur_v = cur_v + leader_ht
1035 end
1036 else
1037 lq = rule_ht / leader_ht
1038 lr = rule_ht % leader_ht
1039 if subtype = = cleaders_code then
1040 cur_v = cur_v + lr / 2
1041 else
1042 ly = lr / ( lq + 1 )
1043 cur_v = cur_v + ( lr - ( lq - 1 ) * ly ) / 2
1044 end
1045 end
1046 while cur_v + leader_ht < = edge do
1047 synch_pos_with_cur ( ref_h , ref_v , getshift ( leader ) , cur_v + height )
1048 outer_doing_leaders = doing_leaders
1049 doing_leaders = true
1050 if getid ( leader ) = = vlist_code then
1051 vlist_out ( leader )
1052 else
1053 hlist_out ( leader )
1054 end
1055 doing_leaders = outer_doing_leaders
1056 cur_v = cur_v + leader_ht + ly
1057 end
1058 cur_v = edge - 10
1059 else
1060 cur_v = cur_v + rule_ht
1061 end
1062 end
1063 else
1064 cur_v = cur_v + rule_ht
1065 end
1066 elseif id = = hlist_code or id = = vlist_code then
1067
1068 local boxdir = getdirection ( current ) or lefttoright_code
1069 local width , height , depth = getwhd ( current )
1070 local list = getlist ( current )
1071 if list then
1072 local shift , orientation = getshift ( current )
1073 if not orientation then
1074
1075
1076 if boxdir ~ = pos_r then
1077 shift = shift + width
1078 end
1079 synch_pos_with_cur ( ref_h , ref_v , shift , cur_v + height )
1080 if id = = vlist_code then
1081 vlist_out ( current , list )
1082 else
1083 hlist_out ( current , list )
1084 end
1085 elseif orientation = = 0x1000 then
1086 local orientation , xoffset , yoffset = getorientation ( current )
1087
1088
1089 if boxdir ~ = pos_r then
1090 shift = shift + width
1091 end
1092 synch_pos_with_cur ( ref_h , ref_v , shift + xoffset , cur_v + height - yoffset )
1093 if id = = vlist_code then
1094 vlist_out ( current , list )
1095 else
1096 hlist_out ( current , list )
1097 end
1098 else
1099 local orientation , xoffset , yoffset , woffset , hoffset , doffset = getorientation ( current )
1100 local orientation , basepoint_h , basepoint_v = applyanchor ( orientation , shift , height , width , height , depth , woffset , hoffset , doffset , xoffset , yoffset )
1101 if orientation = = 1 then
1102 basepoint_h = basepoint_h + width - height
1103 basepoint_v = basepoint_v - height
1104 elseif orientation = = 2 then
1105 basepoint_h = basepoint_h + width
1106 basepoint_v = basepoint_v + depth - height
1107 elseif orientation = = 3 then
1108 basepoint_h = basepoint_h + height
1109 end
1110 synch_pos_with_cur ( ref_h , ref_v , basepoint_h , cur_v + basepoint_v )
1111 pushorientation ( orientation , pos_h , pos_v , pos_r )
1112 if id = = vlist_code then
1113 vlist_out ( current , list )
1114 else
1115 hlist_out ( current , list )
1116 end
1117 poporientation ( orientation , pos_h , pos_v , pos_r )
1118 end
1119 else
1120
1121
1122
1123
1124
1125
1126
1127
1128 end
1129 cur_v = cur_v + height + depth
1130 elseif id = = kern_code then
1131 cur_v = cur_v + getkern ( current )
1132 elseif id = = rule_code then
1133
1134 local ruledir = getdirection ( current )
1135 local width , height , depth = getwhd ( current )
1136 local left , right = getoffsets ( current )
1137 if not ruledir then
1138 ruledir = pos_r
1139 setdirection ( current , ruledir )
1140 end
1141 if width = = running then
1142 width = boxwidth
1143 end
1144 if left ~ = 0 then
1145 width = width - left
1146 cur_h = cur_h + left
1147 end
1148 if right ~ = 0 then
1149 width = width - right
1150 end
1151 local total = height + depth
1152 if total > 0 and width > 0 then
1153 local size_h = width
1154 local size_v = total
1155 if pos_r = = righttoleft_code then
1156 cur_h = cur_h - size_h
1157 end
1158 flushrule ( current , pos_h , pos_v - size_v , pos_r , size_h , size_v )
1159 end
1160 cur_v = cur_v + total
1161 elseif id = = whatsit_code then
1162
1163 if subtype = = literalwhatsit_code then
1164 flushpdfliteral ( current , pos_h , pos_v )
1165 elseif subtype = = lateluawhatsit_code then
1166 flushlatelua ( current , pos_h , pos_v , cur_h , cur_v )
1167 elseif subtype = = setmatrixwhatsit_code then
1168 flushpdfsetmatrix ( current , pos_h , pos_v )
1169 elseif subtype = = savewhatsit_code then
1170 flushpdfsave ( current , pos_h , pos_v )
1171 elseif subtype = = restorewhatsit_code then
1172 flushpdfrestore ( current , pos_h , pos_v )
1173 elseif subtype = = saveposwhatsit_code then
1174 last_position_x = pos_h
1175 last_position_y = pos_v
1176 elseif subtype = = openwhatsit_code or subtype = = writewhatsit_code or subtype = = closewhatsit_code then
1177 if not doing_leaders then
1178 wrapup_leader ( current , subtype )
1179 end
1180
1181
1182 end
1183 end
1184
1185 synch_pos_with_cur ( ref_h , ref_v , cur_h , cur_v )
1186 end
1187
1188
1189
1190 pos_h = ref_h
1191 pos_v = ref_v
1192 pos_r = ref_r
1193 end
1194
1195end
1196
1197function drivers . convert ( name , box , smode , objnum , specification )
1198
1199 if box then
1200 box = tonut ( box )
1201 else
1202 report ( " error on converter, no box " )
1203 return
1204 end
1205
1206 local driver = instances [ name ]
1207 if driver then
1208
1209 else
1210 return
1211 end
1212
1213 local actions = driver . actions
1214 local flushers = driver . flushers
1215
1216 initialize = actions . initialize
1217 finalize = actions . finalize
1218 updatefontstate = actions . updatefontstate
1219
1220 pushorientation = flushers . pushorientation
1221 poporientation = flushers . poporientation
1222
1223 flushcharacter = flushers . character
1224 flushrule = flushers . rule
1225 flushsimplerule = flushers . simplerule
1226 flushlatelua = flushers . latelua
1227 flushspecial = flushers . special
1228 flushpdfliteral = flushers . pdfliteral
1229 flushpdfsetmatrix = flushers . pdfsetmatrix
1230 flushpdfsave = flushers . pdfsave
1231 flushpdfrestore = flushers . pdfrestore
1232 flushpdfimage = flushers . pdfimage
1233
1234 reset_dir_stack ( )
1235 reset_state ( )
1236
1237 shippingmode = smode
1238
1239
1240
1241
1242
1243
1244
1245 local width , height , depth = getwhd ( box )
1246
1247 local total = height + depth
1248
1249
1250
1251
1252 local max_v = total
1253 local max_h = width
1254
1255 if height > maxdimen or depth > maxdimen or width > maxdimen then
1256 goto DONE
1257 end
1258
1259 if max_v > maxdimen then
1260 goto DONE
1261 elseif max_v > abs_max_v then
1262 abs_max_v = max_v
1263 end
1264
1265 if max_h > maxdimen then
1266 goto DONE
1267 elseif max_h > abs_max_h then
1268 abs_max_h = max_h
1269 end
1270
1271 if shippingmode = = " page " then
1272
1273
1274
1275 local pagewidth , pageheight = getpagedimensions ( )
1276
1277
1278
1279
1280
1281 pos_r = lefttoright_code
1282
1283 if pagewidth > 0 then
1284 page_size_h = pagewidth
1285 else
1286 page_size_h = width
1287 end
1288
1289 if page_size_h = = 0 then
1290 page_size_h = width
1291 end
1292
1293 if pageheight > 0 then
1294 page_size_v = pageheight
1295 else
1296 page_size_v = total
1297 end
1298
1299 if page_size_v = = 0 then
1300 page_size_v = total
1301 end
1302
1303 local refpoint_h = 0
1304 local refpoint_v = page_size_v
1305
1306 synch_pos_with_cur ( refpoint_h , refpoint_v , 0 , height )
1307
1308 else
1309
1310
1311
1312 page_size_h = width
1313 page_size_v = total
1314 pos_r = getdirection ( box )
1315 pos_v = depth
1316 pos_h = pos_r = = righttoleft_code and width or 0
1317
1318 end
1319
1320 shipbox_ref_h = pos_h
1321 shipbox_ref_v = pos_v
1322
1323 initialize {
1324 shippingmode = smode ,
1325 boundingbox = { 0 , 0 , page_size_h , page_size_v } ,
1326 objectnumber = objnum ,
1327 }
1328
1329 if getid ( box ) = = vlist_code then
1330 vlist_out ( box )
1331 else
1332 hlist_out ( box )
1333 end
1334
1335 :: DONE ::
1336
1337
1338
1339
1340
1341 finalize ( objnum , specification )
1342 shippingmode = " none "
1343end
1344
1345
1346
1347
1348
1349
1350
1351local initialized = false
1352local shipouts = { }
1353
1354local function wrapup ( )
1355 statistics . starttiming ( shipouts )
1356 drivers . wrapup ( " pdf " )
1357 statistics . stoptiming ( shipouts )
1358end
1359
1360local function report ( )
1361 return statistics . elapsedseconds ( shipouts )
1362end
1363
1364local function shipout ( boxnumber )
1365 callbacks . functions . start_page_number ( )
1366 statistics . starttiming ( shipouts )
1367 drivers . convert ( " pdf " , tex . box [ boxnumber ] , " page " )
1368 statistics . stoptiming ( shipouts )
1369 callbacks . functions . stop_page_number ( )
1370end
1371
1372
1373
1374local function enableshipout ( )
1375 if not initialized then
1376
1377 updaters . apply ( " backend.update.pdf " )
1378
1379 updaters . apply ( " backend.update.lpdf " )
1380
1381 updaters . apply ( " backend.update.tex " )
1382
1383 updaters . apply ( " backend.update " )
1384
1385 directives . enable ( " graphics.uselua " )
1386
1387 if rawget ( pdf , " setforcefile " ) then
1388 pdf . setforcefile ( false )
1389 end
1390
1391 local pdfname = tex . jobname . . " .pdf "
1392 local tmpname = " l_m_t_x_ " . . pdfname
1393 os . remove ( tmpname )
1394 if lfs . isfile ( tmpname ) then
1395 report ( " file %a can't be opened, aborting " , tmpname )
1396 os . exit ( )
1397 end
1398 lpdf . openfile ( tmpname )
1399
1400 luatex . registerstopactions ( 1 , function ( )
1401 lpdf . finalizedocument ( )
1402 lpdf . closefile ( )
1403 end )
1404
1405 luatex . registerpageactions ( 1 , function ( )
1406 lpdf . finalizepage ( true )
1407 end )
1408
1409 luatex . wrapup ( function ( )
1410 local ok = true
1411 if lfs . isfile ( pdfname ) then
1412 os . remove ( pdfname )
1413 end
1414 if lfs . isfile ( pdfname ) then
1415 ok = false
1416 else
1417 os . rename ( tmpname , pdfname )
1418 if lfs . isfile ( tmpname ) then
1419 ok = false
1420 end
1421 end
1422 if not ok then
1423 print ( formatters [ " \nerror in renaming %a to %a\n " ] ( tmpname , pdfname ) )
1424 end
1425 end )
1426
1427 fonts . constructors . autocleanup = false
1428
1429 lpdf . registerdocumentfinalizer ( wrapup , nil , " wrapping up " )
1430
1431 statistics . register ( " pdf generation time (minus font inclusion) " , report )
1432
1433 environment . lmtxmode = true
1434
1435 initialized = true
1436 end
1437end
1438
1439interfaces . implement {
1440 name = " shipoutpage " ,
1441 arguments = " integer " ,
1442 actions = shipout ,
1443}
1444
1445interfaces . implement {
1446 name = " enableshipout " ,
1447 actions = enableshipout ,
1448}
1449 |