if not modules then modules = { } end modules ['lpdf-rul'] = {
    version   = 1.001,
    comment   = "companion to grph-rul.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- todo: split backend and pdf

local tonumber, tostring, next, type = tonumber, tostring, next, type
local concat, setmetatableindex = table.concat, table.setmetatableindex

local attributes       = attributes
local nodes            = nodes

local bpfactor         <const> = number.dimenfactors.bp

local nuts             = nodes.nuts
local ruleactions      = nuts.rules.ruleactions

local getwhd           = nuts.getwhd

local lefttoright_code <const> = tex.directioncodes.lefttoright

local mpcolor          = attributes.colors.mpcolor

local trace_mp         = false  trackers.register("rules.mp", function(v) trace_mp = v end)

local report_mp        = logs.reporter("rules","mp")

local floor            = math.floor
local getrandom        = utilities.randomizer.get
local formatters       = string.formatters

local setdimen         = tex.setdimen
local isdimen          = tex.isdimen
local setmacro         = tokens.setters.macro

local codeinjections   = backends.registered.pdf.codeinjections

local d_rule_width     <const> = isdimen("d_rule_width")
local d_rule_height    <const> = isdimen("d_rule_height")
local d_rule_depth     <const> = isdimen("d_rule_depth")
local d_rule_h         <const> = isdimen("d_rule_h")
local d_rule_v         <const> = isdimen("d_rule_v")
local d_rule_line      <const> = isdimen("d_rule_line")
local d_rule_offset    <const> = isdimen("d_rule_offset")
local d_rule_factor    <const> = isdimen("d_rule_factor")

-- This is very pdf specific. Maybe move some to lpdf-rul.lua some day.

local pdfprint ; pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end

do

    local simplemetapost = metapost.simple
    local cachesize      = 0
    local maxcachesize   = 256*1024
    local cachethreshold = 1024
    local caching        = false -- otherwise random issues so we need a dedicated randomizer first

 -- local maxcachesize   = 8*1024
 -- local cachethreshold = 1024/2

    local cache = setmetatableindex(function(t,k)
        local v = simplemetapost("rulefun",k) -- w, h, d
        cachesize = cachesize + #v
        if cachesize > maxcachesize then
         -- print("old",cachesize)
            for k, v in next, t do
                local n = #v
                if n > cachethreshold then
                    t[k] = nil
                    cachesize = cachesize - n
                end
            end
         -- print("new",cachesize)
        end
     -- print(cachesize,maxcachesize,cachethreshold,#v)
        t[k] = v
        return v
    end)

    local replacer = utilities.templates.replacer

    -- todo: RuleColor -> just string ?
    -- todo: fetch them instead fo push them

--     local predefined = {
--         ["fake:word"] = replacer [[
-- FakeWord(%width%,%height%,%depth%,%line%,%color%);
--         ]],
--         ["fake:rule"] = replacer[[
-- %initializations%
-- FakeRule(%width%,%height%,%depth%,%line%,%color%);
--         ]],
--         ["fake:rest"] = replacer [[
-- RuleDirection := "%direction%" ;
-- RuleOption := "%option%" ;
-- RuleWidth := %width% ;
-- RuleHeight := %height% ;
-- RuleDepth := %depth% ;
-- RuleH := %h% ;
-- RuleV := %v% ;
-- RuleThickness := %line% ;
-- RuleFactor := %factor% ;
-- RuleOffset := %offset% ;
-- def RuleColor = %color% enddef ;
-- %data%;
--         ]]
--     }

        local predefined = {
        ["fake:word"] = replacer [[
FakeWord(RuleWidth,RuleHeight,RuleDepth,RuleThickness,RuleColor);
        ]],
        ["fake:rule"] = replacer[[
%initializations%
FakeRule(RuleWidth,RuleHeight,RuleDepth,RuleThickness,RuleColor);
        ]],
        ["fake:rest"] = replacer [[
%data%;
        ]]
    }

    local initialized = false ;

    local function rule_mp(p,h,v,i,n)
        local name  = p.name or "fake:rest"
        local ht    = p.height or 0
        local dp    = p.depth  or 0
        local total = ht + dp
        local code  = (predefined[name] or predefined["fake:rest"]) {
            data      = p.data or "",
      -- -- width     = p.width * bpfactor,
      -- -- height    = p.height * bpfactor,
      -- -- depth     = p.depth * bpfactor,
      --    width     = h * bpfactor,
      --    height    = v * bpfactor * ht / total,
      --    depth     = v * bpfactor * dp / total,
      --    factor    = (p.factor or 0) * bpfactor, -- needs checking
      --    offset    = p.offset or 0,
      --    line      = (p.line or 65536) * bpfactor,
      --    color     = mpcolor(p.ma,p.ca,p.ta),
      --    option    = p.option or "",
      --    direction = p.direction or lefttoright_code,
      --    h         = h * bpfactor,
      --    v         = v * bpfactor,
        }
        --
        setdimen("d_rule_width", h)
        setdimen("d_rule_height", v * ht / total)
        setdimen("d_rule_depth", v * dp / total)
        setdimen("d_rule_height", ht)
        setdimen("d_rule_depth", dp)
        setdimen("d_rule_h", h)
        setdimen("d_rule_v", v)
        setdimen("d_rule_line", p.line or 65536)
        setdimen("d_rule_offset", (p.offset or 0) * 65536)
        setdimen("d_rule_factor", (p.factor or 0)) -- needs checking
        setmacro("m_rule_option", p.option or "")
        setmacro("m_rule_direction", p.direction or lefttoright_code)
        setmacro("m_rule_color", mpcolor(p.ma,p.ca,p.ta))
        --
        if not initialized then
            initialized = true
            simplemetapost("rulefun",formatters["randomseed := %s;"](getrandom("rulefun",0,4095)))
        end
        -- we enable extensions but we could also consider to delegate colors
        -- to the node finalizer
        local pdf = caching and cache[code] or simplemetapost("rulefun",code,true)
        if trace_mp then
            report_mp("code: %s",code)
            report_mp("pdf : %s",pdf)
        end
        if pdf and pdf ~= "" then
            pdfprint("direct",pdf)
        end
    end

    codeinjections.ruleactionmp = rule_mp

end

do

    -- This is the old oval method that we keep it for compatibility reasons. Of course one can use mp
    -- instead. It could be improved but at the cost of more code than I'm willing to add for something
    -- hardly used.

    local linemapping = {
        [interfaces.variables.round] = "ltrb",
        [ "0"] = "ltrb", ["ltrb"] = "ltrb", ["trbl"] = "ltrb", ["rblt"] = "ltrb", ["bltr"] = "ltrb",
        --
        ["1"] = "ltrb", ["2"] = "ltrb", ["3"] = "ltrb", ["4"] = "ltrb",
        ["5"] = "ltrb", ["6"] = "ltrb", ["7"] = "ltrb", ["8"] = "ltrb",
        --
        [ "9"] = "trb", ["trb"] = "trb", ["rtl"] = "trb",
        ["10"] = "tlb", ["tlb"] = "tlb", ["blt"] = "tlb",
        ["11"] = "ltr", ["ltr"] = "ltr", ["rtl"] = "lrt",
        ["12"] = "lbr", ["lbr"] = "lbr", ["rbl"] = "lbr",
        --
        ["13"] = "rt", ["rt"] = "rt", ["tr"] = "rt",
        ["14"] = "rb", ["rb"] = "rb", ["br"] = "rb",
        ["15"] = "bl", ["bl"] = "bl", ["lb"] = "bl",
        ["16"] = "tl", ["tl"] = "tl", ["lt"] = "tl",
        --
        ["32"] = "lr", ["lr"] = "lr", ["rl"] = "lr",
        ["33"] = "tb", ["tb"] = "tb", ["bt"] = "tb",
        --
        ["28"] = "l", ["l"] = "l",
        ["29"] = "r", ["r"] = "r",
        ["30"] = "b", ["b"] = "b",
        ["31"] = "t", ["t"] = "t",
    }

    local roundmapping = {
        [interfaces.variables.round] = "ltrb",
        [ "0"] = "ltrb", ["ltrb"] = "ltrb", ["trbl"] = "ltrb", ["rblt"] = "ltrb", ["bltr"] = "ltrb",
        --
        [ "9"] = "trb", ["trb"] = "trb", ["rtl"] = "trb",
        ["10"] = "tlb", ["tlb"] = "tlb", ["blt"] = "tlb",
        ["11"] = "ltr", ["ltr"] = "ltr", ["rtl"] = "lrt",
        ["12"] = "lbr", ["lbr"] = "lbr", ["rbl"] = "lbr",
        --
        ["13"] = "rt", ["rt"] = "rt", ["tr"] = "rt",
        ["14"] = "rb", ["rb"] = "rb", ["br"] = "rb",
        ["15"] = "bl", ["bl"] = "bl", ["lb"] = "bl",
        ["16"] = "tl", ["tl"] = "tl", ["lt"] = "tl",
        --
        ["32"] = "lr", ["lr"] = "lr", ["rl"] = "lr",
        ["33"] = "tb", ["tb"] = "tb", ["bt"] = "tb",
        --
        ["28"] = "l", ["l"] = "l",
        ["29"] = "r", ["r"] = "r",
        ["30"] = "b", ["b"] = "b",
        ["31"] = "t", ["t"] = "t",
    }

    local function register(t,k)
        local v = tonumber(k)
        if v then
            v = tostring(v)
        end
        v = v and rawget(t,v) or v
        if not v then
            v = "ltrb"
        end
        t[k] = v
        return v
    end

    setmetatableindex(linemapping, register)
    setmetatableindex(roundmapping,register)

    local function round(p,kind,corner)
        local width  = p.width or 0
        local height = p.height or 0
        local depth  = p.depth or 0
        local radius = p.radius or 655360
        local line   = (p.line or 65536) * bpfactor
        local half   = line / 2
        local xxmin  = 0
        local xxmax  =  width * bpfactor
        local yymax  = height * bpfactor
        local yymin  = -depth * bpfactor
        local xmin   = xxmin + half
        local xmax   = xxmax - half
        local ymax   = yymax - half
        local ymin   = yymin + half
        local list   = nil
        local done   = kind ~= "fill" and "S" or "f"
        if radius == 0 then
            local method = linemapping[corner]
            if method == "ltrb" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l h %s Q"]
                    (line,xmin,ymin,xmax,ymin,xmax,ymax,xmin,ymax,done)
            elseif method == "l" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
                    (line,xmin,yymin,xmin,yymax)
            elseif method == "r" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
                    (line,xmax,yymin,xmax,yymax)
            elseif method == "b" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
                    (line,xxmin,ymin,xxmax,ymin)
            elseif method == "t" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l S Q"]
                    (line,xxmin,ymax,xxmax,ymax)
            elseif method == "lr" then
                list = formatters
                    ["q %.6N w %.6N  %.6N m %.6N  %.6N l %.6N  %.6N m %.6N  %.6N  %.6N l S Q"]
                    (line,xmin,yymin,xmin,yymax,xmax,yymin,xmax,yymax)
            elseif method == "tb" then
                list = formatters
                    ["q %.6N w %.6N  %.6N m %.6N  %.6N l %.6N  %.6N m %.6N  %.6N  %.6N l S Q"]
                    (line,xxmin,ymin,xxmax,ymin,xxmin,ymax,xxmax,ymax)
            elseif method == "lbr" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xmin,yymax,xmin,ymin,xmax,ymin,xmax,yymax)
            elseif method == "tlb" then -- 10
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xxmax,ymax,xmin,ymax,xmin,ymin,xxmax,ymin)
            elseif method == "ltr" then -- 11
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xmin,yymin,xmin,ymax,xmax,ymax,xmax,yymin)
            elseif method == "trb" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xxmin,ymax,xmax,ymax,xmax,ymin,xxmin,ymin)
            elseif method == "rt" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xxmin,ymax,xmax,ymax,xmax,yymin)
            elseif method == "rb" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xmax,yymax,xmax,ymin,xxmin,ymin)
            elseif method == "bl" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xxmax,ymin,xmin,ymin,xmin,yymax)
            elseif method == "tl" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N l S Q"]
                    (line,xmin,yymin,xmin,ymax,xxmax,ymax)
            else
                return
            end
        else
            local method = roundmapping[corner]
            local full   = ( radius + half)
            local xxxmin =            full  * bpfactor
            local xxxmax = ( width  - full) * bpfactor
            local yyymax = ( height - full) * bpfactor
            local yyymin = (-depth  + full) * bpfactor
            if xxxmin > xxxmax or yyymin > yyymax then
                return
            elseif method == "ltrb" then
                list = 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"]
                    (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)
            elseif method == "1" then -- ll lr
                list = formatters
                    ["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"]
                    (line,xxxmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,ymax,xmin,ymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
            elseif method == "2" then -- ll ul
                list = formatters
                    ["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"]
                    (line,xxxmin,ymin,xmax,ymin,xmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
            elseif method == "3" then -- ul ur
                list = formatters
                    ["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"]
                    (line,xmin,ymin,xmax,ymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,ymin,done)
            elseif method == "4" then -- ur lr
                list = 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 l h %s Q"]
                    (line,xmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xmin,ymax,xmin,ymin,done)
            elseif method == "5" then -- ur
                list = formatters
                    ["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"]
                    (line,xmin,ymin,xmax,ymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xmin,ymax,xmin,ymin,done)
            elseif method == "6" then -- lr
                list = formatters
                    ["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"]
                    (line,xmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,ymax,xmin,ymax,xmin,ymin,done)
            elseif method == "7" then -- ur
                list = formatters
                    ["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
                    (line,xxxmin,ymin,xmax,ymin,xmax,ymax,xmin, ymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,done)
            elseif method == "8" then -- ul
                list = formatters
                    ["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"]
                    (line,xmin,ymin,xmax,ymin,xmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,ymin,done)
            elseif method == "lbr" then -- 12
                list = 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 S Q"]
                    (line,xmin,yymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,xxxmax,ymin,xmax,ymin,xmax,yyymin,xmax,yymax)
            elseif method == "tlb" then -- 10
                list = 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 S Q"]
                    (line,xxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yyymin,xmin,ymin,xxxmin,ymin,xxmax,ymin)
            elseif method == "ltr" then -- 11
                list = 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 S Q"]
                    (line,xmax,yymin,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax,xmin,yymin)
            elseif method == "trb" then -- 9
                list = 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 S Q"]
                    (line,xxmin,ymax,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxmin,ymin)
            elseif method == "lr" then
                list = formatters
                    ["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"]
                    (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)
            elseif method == "tb" then
                list = formatters
                    ["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"]
                    (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)
            elseif method == "rt" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
                    (line,xxmin,ymax,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yymin)
            elseif method == "rb" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
                    (line,xmax,yymax,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxmin,ymin)
            elseif method == "bl" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
                    (line,xxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yymax)
            elseif method == "tl" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N l %.6N %.6N %.6N %.6N y %.6N %.6N l S Q"]
                    (line,xmin,yymin,xmin,yyymax,xmin,ymax,xxxmin,ymax,xxmax,ymax)
            elseif method == "17" then -- urx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax)
            elseif method == "18" then -- lrt
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin)
            elseif method == "19" then -- llx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin)
            elseif method == "20" then -- urx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmin,yyymax,xmin,ymax,xxxmin,ymax)
            elseif method == "21" then -- ulx urx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax)
            elseif method == "22" then -- urt lrt
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin)
            elseif method == "23" then -- llx lrx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin)
            elseif method == "24" then -- ulx llx
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
            elseif method == "25" then -- llx lrx urx ulx
                list = formatters
                    ["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"]
                    (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)
            elseif method == "26" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
            elseif method == "27" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N m %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xxxmin,ymin,xmin,ymin,xmin,yyymin)
            elseif method == "l" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmin,ymin,xmin,ymin,xmin,yyymin,xmin,yyymax,xmin,ymax,xxxmin,ymax)
            elseif method == "r" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
                    (line,xxxmax,ymax,xmax,ymax,xmax,yyymax,xmax,yyymin,xmax,ymin,xxxmax,ymin)
            elseif method == "b" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymin,xmax,ymin,xxxmax,ymin,xxxmin,ymin,xmin,ymin,xmin,yyymin)
            elseif method == "t" then
                list = formatters
                    ["q %.6N w %.6N %.6N m %.6N %.6N %.6N %.6N y %.6N %.6N l %.6N %.6N %.6N %.6N y S Q"]
                    (line,xmax,yyymax,xmax,ymax,xxxmax,ymax,xxxmin,ymax,xmin,ymax,xmin,yyymax)
             else
                return
            end
        end
     -- print(list)
        pdfprint("direct",list)
    end

    local f_rectangle = formatters["q %.6N w %.6N %.6N %.6N %.6N re %s Q"]
    local f_baselined = formatters["q %.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s Q"]
    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"]
    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"]
    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"]

    local rule_any = function(p,h,v,i,n)
        local corner = p.corner
        if corner then
            return round(p,i,corner)
        else
            local l = (p.line or 65536)*bpfactor
            local r = p and (p.radius or 0)*bpfactor or 0
            local w = h * bpfactor
            local h = v * bpfactor
            local m = nil
            local t = i == "fill" and "f" or "s"
            local o = l / 2
            if r > 0 then
                w = w - o
                h = h - o
                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)
            else
                w = w - l
                h = h - l
                m = f_rectangle(l,o,o,w,h,t)
            end
            pdfprint("direct",m)
        end
    end

    local function rule_box(p,h,v,i,n)
        local w, h, d = getwhd(n)
        local line = p.line or 65536
        local l = line *bpfactor
        local w = w * bpfactor
        local h = h * bpfactor
        local d = d * bpfactor
        local o = l / 2
        local u = p.double
        if p.baseline ~= false and ((d >= 0 and h >= 0) or (d <= 0 and h <= 0)) then
            local dashed = tonumber(p.dashed)
            if dashed and dashed > 5*line then
                dashed = dashed * bpfactor
                local delta = (w - 2*dashed*floor(w/(2*dashed)))/2
                if u then
                    u = u * bpfactor
                    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))
                else
                    pdfprint("direct",f_dashlined(l,o,o,w-l,h+d-l,dashed,dashed,delta,d,w-delta,d))
                end
            else
                pdfprint("direct",f_baselined(l,o,o,w-l,h+d-l,0,d,w,d))
            end
        else
            pdfprint("direct",f_rectangle(l,o,o,w-l,h+d-l,"s"))
        end
    end

    codeinjections.ruleactionfill   = rule_any
    codeinjections.ruleactiondraw   = rule_any
    codeinjections.ruleactionstroke = rule_any
    codeinjections.ruleactionbox    = rule_box

end

