lpdf-rul.lmt /size: 25 Kb    last modification: 2024-01-16 09:02
1if not modules then modules = { } end modules ['lpdf-rul'] = {
2    version   = 1.001,
3    comment   = "companion to grph-rul.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-- todo: split backend and pdf
10
11local tonumber, tostring, next, type = tonumber, tostring, next, type
12local concat, setmetatableindex = table.concat, table.setmetatableindex
13
14local attributes       = attributes
15local nodes            = nodes
16
17local bpfactor         = number.dimenfactors.bp
18
19local nuts             = nodes.nuts
20local ruleactions      = nuts.rules.ruleactions
21
22local getwhd           = nuts.getwhd
23
24local lefttoright_code = tex.directioncodes.lefttoright
25
26local mpcolor          = attributes.colors.mpcolor
27
28local trace_mp         = false  trackers.register("rules.mp", function(v) trace_mp = v end)
29
30local report_mp        = logs.reporter("rules","mp")
31
32local floor            = math.floor
33local getrandom        = utilities.randomizer.get
34local formatters       = string.formatters
35
36local setdimen         = tex.setdimen
37local isdimen          = tex.isdimen
38local setmacro         = tokens.setters.macro
39
40local codeinjections   = backends.registered.pdf.codeinjections
41
42local d_rule_width  = isdimen("d_rule_width")
43local d_rule_height = isdimen("d_rule_height")
44local d_rule_depth  = isdimen("d_rule_depth")
45local d_rule_h      = isdimen("d_rule_h")
46local d_rule_v      = isdimen("d_rule_v")
47local d_rule_line   = isdimen("d_rule_line")
48local d_rule_offset = isdimen("d_rule_offset")
49local d_rule_factor = isdimen("d_rule_factor")
50
51-- This is very pdf specific. Maybe move some to lpdf-rul.lua some day.
52
53local pdfprint ; pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end
54
55do
56
57    local simplemetapost = metapost.simple
58    local cachesize      = 0
59    local maxcachesize   = 256*1024
60    local cachethreshold = 1024
61    local caching        = false -- otherwise random issues so we need a dedicated randomizer first
62
63 -- local maxcachesize   = 8*1024
64 -- local cachethreshold = 1024/2
65
66    local cache = setmetatableindex(function(t,k)
67        local v = simplemetapost("rulefun",k) -- w, h, d
68        cachesize = cachesize + #v
69        if cachesize > maxcachesize then
70         -- print("old",cachesize)
71            for k, v in next, t do
72                local n = #v
73                if n > cachethreshold then
74                    t[k] = nil
75                    cachesize = cachesize - n
76                end
77            end
78         -- print("new",cachesize)
79        end
80     -- print(cachesize,maxcachesize,cachethreshold,#v)
81        t[k] = v
82        return v
83    end)
84
85    local replacer = utilities.templates.replacer
86
87    -- todo: RuleColor -> just string ?
88    -- todo: fetch them instead fo push them
89
90--     local predefined = {
91--         ["fake:word"] = replacer [[
92-- FakeWord(%width%,%height%,%depth%,%line%,%color%);
93--         ]],
94--         ["fake:rule"] = replacer[[
95-- %initializations%
96-- FakeRule(%width%,%height%,%depth%,%line%,%color%);
97--         ]],
98--         ["fake:rest"] = replacer [[
99-- RuleDirection := "%direction%" ;
100-- RuleOption := "%option%" ;
101-- RuleWidth := %width% ;
102-- RuleHeight := %height% ;
103-- RuleDepth := %depth% ;
104-- RuleH := %h% ;
105-- RuleV := %v% ;
106-- RuleThickness := %line% ;
107-- RuleFactor := %factor% ;
108-- RuleOffset := %offset% ;
109-- def RuleColor = %color% enddef ;
110-- %data%;
111--         ]]
112--     }
113
114        local predefined = {
115        ["fake:word"] = replacer [[
116FakeWord(RuleWidth,RuleHeight,RuleDepth,RuleThickness,RuleColor);
117        ]],
118        ["fake:rule"] = replacer[[
119%initializations%
120FakeRule(RuleWidth,RuleHeight,RuleDepth,RuleThickness,RuleColor);
121        ]],
122        ["fake:rest"] = replacer [[
123%data%;
124        ]]
125    }
126
127    local initialized = false ;
128
129    local function rule_mp(p,h,v,i,n)
130        local name  = p.name or "fake:rest"
131        local ht    = p.height or 0
132        local dp    = p.depth  or 0
133        local total = ht + dp
134        local code  = (predefined[name] or predefined["fake:rest"]) {
135            data      = p.data or "",
136      -- -- width     = p.width * bpfactor,
137      -- -- height    = p.height * bpfactor,
138      -- -- depth     = p.depth * bpfactor,
139      --    width     = h * bpfactor,
140      --    height    = v * bpfactor * ht / total,
141      --    depth     = v * bpfactor * dp / total,
142      --    factor    = (p.factor or 0) * bpfactor, -- needs checking
143      --    offset    = p.offset or 0,
144      --    line      = (p.line or 65536) * bpfactor,
145      --    color     = mpcolor(p.ma,p.ca,p.ta),
146      --    option    = p.option or "",
147      --    direction = p.direction or lefttoright_code,
148      --    h         = h * bpfactor,
149      --    v         = v * bpfactor,
150        }
151        --
152        setdimen("d_rule_width", h)
153        setdimen("d_rule_height", v * ht / total)
154        setdimen("d_rule_depth", v * dp / total)
155        setdimen("d_rule_h", h)
156        setdimen("d_rule_v", v)
157        setdimen("d_rule_line", p.line or 65536)
158        setdimen("d_rule_offset", (p.offset or 0) * 65536)
159        setdimen("d_rule_factor", (p.factor or 0)) -- needs checking
160        setmacro("m_rule_option", p.option or "")
161        setmacro("m_rule_direction", p.direction or lefttoright_code)
162        setmacro("m_rule_color", mpcolor(p.ma,p.ca,p.ta))
163        --
164        if not initialized then
165            initialized = true
166            simplemetapost("rulefun",formatters["randomseed := %s;"](getrandom("rulefun",0,4095)))
167        end
168        -- we enable extensions but we could also consider to delegate colors
169        -- to the node finalizer
170        local pdf = caching and cache[code] or simplemetapost("rulefun",code,true)
171        if trace_mp then
172            report_mp("code: %s",code)
173            report_mp("pdf : %s",pdf)
174        end
175        if pdf and pdf ~= "" then
176            pdfprint("direct",pdf)
177        end
178    end
179
180    codeinjections.ruleactionmp = rule_mp
181
182end
183
184do
185
186    -- This is the old oval method that we keep it for compatibility reasons. Of course one can use mp
187    -- instead. It could be improved but at the cost of more code than I'm willing to add for something
188    -- hardly used.
189
190    local linemapping = {
191        [interfaces.variables.round] = "ltrb",
192        [ "0"] = "ltrb", ["ltrb"] = "ltrb", ["trbl"] = "ltrb", ["rblt"] = "ltrb", ["bltr"] = "ltrb",
193        --
194        ["1"] = "ltrb", ["2"] = "ltrb", ["3"] = "ltrb", ["4"] = "ltrb",
195        ["5"] = "ltrb", ["6"] = "ltrb", ["7"] = "ltrb", ["8"] = "ltrb",
196        --
197        [ "9"] = "trb", ["trb"] = "trb", ["rtl"] = "trb",
198        ["10"] = "tlb", ["tlb"] = "tlb", ["blt"] = "tlb",
199        ["11"] = "ltr", ["ltr"] = "ltr", ["rtl"] = "lrt",
200        ["12"] = "lbr", ["lbr"] = "lbr", ["rbl"] = "lbr",
201        --
202        ["13"] = "rt", ["rt"] = "rt", ["tr"] = "rt",
203        ["14"] = "rb", ["rb"] = "rb", ["br"] = "rb",
204        ["15"] = "bl", ["bl"] = "bl", ["lb"] = "bl",
205        ["16"] = "tl", ["tl"] = "tl", ["lt"] = "tl",
206        --
207        ["32"] = "lr", ["lr"] = "lr", ["rl"] = "lr",
208        ["33"] = "tb", ["tb"] = "tb", ["bt"] = "tb",
209        --
210        ["28"] = "l", ["l"] = "l",
211        ["29"] = "r", ["r"] = "r",
212        ["30"] = "b", ["b"] = "b",
213        ["31"] = "t", ["t"] = "t",
214    }
215
216    local roundmapping = {
217        [interfaces.variables.round] = "ltrb",
218        [ "0"] = "ltrb", ["ltrb"] = "ltrb", ["trbl"] = "ltrb", ["rblt"] = "ltrb", ["bltr"] = "ltrb",
219        --
220        [ "9"] = "trb", ["trb"] = "trb", ["rtl"] = "trb",
221        ["10"] = "tlb", ["tlb"] = "tlb", ["blt"] = "tlb",
222        ["11"] = "ltr", ["ltr"] = "ltr", ["rtl"] = "lrt",
223        ["12"] = "lbr", ["lbr"] = "lbr", ["rbl"] = "lbr",
224        --
225        ["13"] = "rt", ["rt"] = "rt", ["tr"] = "rt",
226        ["14"] = "rb", ["rb"] = "rb", ["br"] = "rb",
227        ["15"] = "bl", ["bl"] = "bl", ["lb"] = "bl",
228        ["16"] = "tl", ["tl"] = "tl", ["lt"] = "tl",
229        --
230        ["32"] = "lr", ["lr"] = "lr", ["rl"] = "lr",
231        ["33"] = "tb", ["tb"] = "tb", ["bt"] = "tb",
232        --
233        ["28"] = "l", ["l"] = "l",
234        ["29"] = "r", ["r"] = "r",
235        ["30"] = "b", ["b"] = "b",
236        ["31"] = "t", ["t"] = "t",
237    }
238
239    local function register(t,k)
240        local v = tonumber(k)
241        if v then
242            v = tostring(v)
243        end
244        v = v and rawget(t,v) or v
245        if not v then
246            v = "ltrb"
247        end
248        t[k] = v
249        return v
250    end
251
252    setmetatableindex(linemapping, register)
253    setmetatableindex(roundmapping,register)
254
255    local function round(p,kind,corner)
256        local width  = p.width or 0
257        local height = p.height or 0
258        local depth  = p.depth or 0
259        local radius = p.radius or 655360
260        local line   = (p.line or 65536) * bpfactor
261        local half   = line / 2
262        local xxmin  = 0
263        local xxmax  =  width * bpfactor
264        local yymax  = height * bpfactor
265        local yymin  = -depth * bpfactor
266        local xmin   = xxmin + half
267        local xmax   = xxmax - half
268        local ymax   = yymax - half
269        local ymin   = yymin + half
270        local list   = nil
271        local done   = kind ~= "fill" and "S" or "f"
272        if radius == 0 then
273            local method = linemapping[corner]
274            if method == "ltrb" then
275                list = formatters
276                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l h %s Q"]
277                    (line,xmin,ymin,xmax,ymin,xmax,ymax,xmin,ymax,done)
278            elseif method == "l" then
279                list = formatters
280                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
281                    (line,xmin,yymin,xmin,yymax)
282            elseif method == "r" then
283                list = formatters
284                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
285                    (line,xmax,yymin,xmax,yymax)
286            elseif method == "b" then
287                list = formatters
288                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
289                    (line,xxmin,ymin,xxmax,ymin)
290            elseif method == "t" then
291                list = formatters
292                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
293                    (line,xxmin,ymax,xxmax,ymax)
294            elseif method == "lr" then
295                list = formatters
296                    ["q %.6N w %.6N  %.6N m %.6N  %.6N l %.6N  %.6N m %.6N  %.6N  %.6N l S Q"]
297                    (line,xmin,yymin,xmin,yymax,xmax,yymin,xmax,yymax)
298            elseif method == "tb" then
299                list = formatters
300                    ["q %.6N w %.6N  %.6N m %.6N  %.6N l %.6N  %.6N m %.6N  %.6N  %.6N l S Q"]
301                    (line,xxmin,ymin,xxmax,ymin,xxmin,ymax,xxmax,ymax)
302            elseif method == "lbr" then
303                list = formatters
304                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
305                    (line,xmin,yymax,xmin,ymin,xmax,ymin,xmax,yymax)
306            elseif method == "tlb" then -- 10
307                list = formatters
308                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
309                    (line,xxmax,ymax,xmin,ymax,xmin,ymin,xxmax,ymin)
310            elseif method == "ltr" then -- 11
311                list = formatters
312                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
313                    (line,xmin,yymin,xmin,ymax,xmax,ymax,xmax,yymin)
314            elseif method == "trb" then
315                list = formatters
316                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
317                    (line,xxmin,ymax,xmax,ymax,xmax,ymin,xxmin,ymin)
318            elseif method == "rt" then
319                list = formatters
320                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
321                    (line,xxmin,ymax,xmax,ymax,xmax,yymin)
322            elseif method == "rb" then
323                list = formatters
324                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
325                    (line,xmax,yymax,xmax,ymin,xxmin,ymin)
326            elseif method == "bl" then
327                list = formatters
328                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
329                    (line,xxmax,ymin,xmin,ymin,xmin,yymax)
330            elseif method == "tl" then
331                list = formatters
332                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
333                    (line,xmin,yymin,xmin,ymax,xxmax,ymax)
334            else
335                return
336            end
337        else
338            local method = roundmapping[corner]
339            local full   = ( radius + half)
340            local xxxmin =            full  * bpfactor
341            local xxxmax = ( width  - full) * bpfactor
342            local yyymax = ( height - full) * bpfactor
343            local yyymin = (-depth  + full) * bpfactor
344            if xxxmin > xxxmax or yyymin > yyymax then
345                return
346            elseif method == "ltrb" then
347                list = formatters
348                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y h %s Q"]
349                    (line,xxxmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
350            elseif method == "1" then -- ll lr
351                list = formatters
352                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y h %s Q"]
353                    (line,xxxmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,ymax,xmin,ymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
354            elseif method == "2" then -- ll ul
355                list = formatters
356                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y h %s Q"]
357                    (line,xxxmin,ymin,xmax,ymin,xmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
358            elseif method == "3" then -- ul ur
359                list = formatters
360                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l h %s Q"]
361                    (line,xmin,ymin,xmax,ymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,ymin,done)
362            elseif method == "4" then -- ur lr
363                list = formatters
364                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N l h %s Q"]
365                    (line,xmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xmin,ymax,xmin,ymin,done)
366            elseif method == "5" then -- ur
367                list = formatters
368                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N l h %s Q"]
369                    (line,xmin,ymin,xmax,ymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xmin,ymax,xmin,ymin,done)
370            elseif method == "6" then -- lr
371                list = formatters
372                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N l %.6N %.6N l h %s Q"]
373                    (line,xmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,ymax,xmin,ymax,xmin,ymin,done)
374            elseif method == "7" then -- ur
375                list = formatters
376                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y h %s Q"] -- outlier
377                    (line,xxxmin,ymin,xmax,ymin,xmax,ymax,xmin, ymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
378            elseif method == "8" then -- ul
379                list = formatters
380                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l h %s Q"]
381                    (line,xmin,ymin,xmax,ymin,xmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,ymin,done)
382            elseif method == "lbr" then -- 12
383                list = formatters
384                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
385                    (line,xmin,yymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,yymax)
386            elseif method == "tlb" then -- 10
387                list = formatters
388                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
389                    (line,xxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,xxmax,ymin)
390            elseif method == "ltr" then -- 11
391                list = formatters
392                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
393                    (line,xmax,yymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yymin)
394            elseif method == "trb" then -- 9
395                list = formatters
396                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
397                    (line,xxmin,ymax,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxmin,ymin)
398            elseif method == "lr" then
399                list = formatters
400                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
401                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin)
402            elseif method == "tb" then
403                list = formatters
404                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
405                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax)
406            elseif method == "rt" then
407                list = formatters
408                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
409                    (line,xxmin,ymax,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yymin)
410            elseif method == "rb" then
411                list = formatters
412                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
413                    (line,xmax,yymax,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxmin,ymin)
414            elseif method == "bl" then
415                list = formatters
416                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
417                    (line,xxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yymax)
418            elseif method == "tl" then
419                list = formatters
420                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
421                    (line,xmin,yymin,xmin,yyymax,xmin,ymax,xxxmin,ymax,xxmax,ymax)
422            elseif method == "17" then -- urx
423                list = formatters
424                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
425                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax)
426            elseif method == "18" then -- lrt
427                list = formatters
428                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
429                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin)
430            elseif method == "19" then -- llx
431                list = formatters
432                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
433                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin)
434            elseif method == "20" then -- urx
435                list = formatters
436                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
437                    (line,xmin,yyymax,xmin,ymax,xxxmin,ymax)
438            elseif method == "21" then -- ulx urx
439                list = formatters
440                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
441                    (line,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax)
442            elseif method == "22" then -- urt lrt
443                list = formatters
444                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
445                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin)
446            elseif method == "23" then -- llx lrx
447                list = formatters
448                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
449                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin)
450            elseif method == "24" then -- ulx llx
451                list = formatters
452                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
453                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
454            elseif method == "25" then -- llx lrx urx ulx
455                list = formatters
456                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
457                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
458            elseif method == "26" then
459                list = formatters
460                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
461                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
462            elseif method == "27" then
463                list = formatters
464                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
465                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xxxmin,ymin,xmin,ymin,xmin,yyymin)
466            elseif method == "l" then
467                list = formatters
468                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
469                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
470            elseif method == "r" then
471                list = formatters
472                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
473                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin)
474            elseif method == "b" then
475                list = formatters
476                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
477                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin)
478            elseif method == "t" then
479                list = formatters
480                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
481                    (line,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax)
482             else
483                return
484            end
485        end
486     -- print(list)
487        pdfprint("direct",list)
488    end
489
490    local f_rectangle = formatters["q %.6N w %.6N %.6N %.6N %.6N re %s Q"]
491    local f_baselined = formatters["q %.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s Q"]
492    local f_dashlined = formatters["q %.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s Q"]
493    local f_dashtwice = formatters["q %.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s %.6N %.6N m %.6N %.6N l s Q"]
494    local f_radtangle = formatters["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y h %s Q"]
495
496    local rule_any = function(p,h,v,i,n)
497        local corner = p.corner
498        if corner then
499            return round(p,i,corner)
500        else
501            local l = (p.line or 65536)*bpfactor
502            local r = p and (p.radius or 0)*bpfactor or 0
503            local w = h * bpfactor
504            local h = v * bpfactor
505            local m = nil
506            local t = i == "fill" and "f" or "s"
507            local o = l / 2
508            if r > 0 then
509                w = w - o
510                h = h - o
511                m = f_radtangle(l, r,o, w-r,o, w,o,w,r, w,h-r, w,h,w-r,h, r,h, o,h,o,h-r, o,r, o,o,r,o, t)
512            else
513                w = w - l
514                h = h - l
515                m = f_rectangle(l,o,o,w,h,t)
516            end
517            pdfprint("direct",m)
518        end
519    end
520
521    local function rule_box(p,h,v,i,n)
522        local w, h, d = getwhd(n)
523        local line = p.line or 65536
524        local l = line *bpfactor
525        local w = w * bpfactor
526        local h = h * bpfactor
527        local d = d * bpfactor
528        local o = l / 2
529        local u = p.double
530        if p.baseline ~= false and ((d >= 0 and h >= 0) or (d <= 0 and h <= 0)) then
531            local dashed = tonumber(p.dashed)
532            if dashed and dashed > 5*line then
533                dashed = dashed * bpfactor
534                local delta = (w - 2*dashed*floor(w/(2*dashed)))/2
535                if u then
536                    u = u * bpfactor
537                    pdfprint("direct",f_dashtwice(l,o,o,w-l,h+d-l,dashed,dashed,delta,d,w-delta,d,delta,d+u,w-delta,d+u))
538                else
539                    pdfprint("direct",f_dashlined(l,o,o,w-l,h+d-l,dashed,dashed,delta,d,w-delta,d))
540                end
541            else
542                pdfprint("direct",f_baselined(l,o,o,w-l,h+d-l,0,d,w,d))
543            end
544        else
545            pdfprint("direct",f_rectangle(l,o,o,w-l,h+d-l,"s"))
546        end
547    end
548
549    codeinjections.ruleactionfill   = rule_any
550    codeinjections.ruleactiondraw   = rule_any
551    codeinjections.ruleactionstroke = rule_any
552    codeinjections.ruleactionbox    = rule_box
553
554end
555
556