if not modules then modules = { } end modules ['font-ocl'] = {
    version   = 1.001,
    comment   = "companion to font-otf.lua (context)",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- todo : user list of colors

local tostring, next = tostring, next

local formatters = string.formatters

local otf = fonts.handlers.otf

local f_color_start = formatters["pdf:direct: %f %f %f rg"]
local s_color_stop  = "pdf:direct:"

if context then

    local startactualtext = nil
    local stopactualtext  = nil

    function otf.getactualtext(n)
        if not startactualtext then
            startactualtext = backends.codeinjections.startunicodetoactualtext
            stopactualtext  = backends.codeinjections.stopunicodetoactualtext
        end
        return startactualtext(n), stopactualtext()
    end

else

    local tounicode = fonts.mappings.tounicode16

    function otf.getactualtext(n)
        return "/Span << /ActualText <feff" .. tounicode(n) .. "> >> BDC", "EMC"
    end

end

local function initializecolr(tfmdata,kind,value) -- hm, always value
    if value then
        local palettes = tfmdata.resources.colorpalettes
        if palettes then
            --
            local palette = palettes[tonumber(value) or 1] or palettes[1] or { }
            local classes = #palette
            if classes == 0 then
                return
            end
            --
            local characters   = tfmdata.characters
            local descriptions = tfmdata.descriptions
            local properties   = tfmdata.properties
            local colorvalues  = { }
            --
            properties.virtualized = true
            tfmdata.fonts = {
                { id = 0 }
            }
            --
            for i=1,classes do
                local p = palette[i]
                colorvalues[i] = { "special", f_color_start(p[1]/255,p[2]/255,p[3]/255) }
            end
            --
            local getactualtext = otf.getactualtext
            --
            for unicode, character in next, characters do
                local description = descriptions[unicode]
                if description then
                    local colorlist = description.colors
                    if colorlist then
                        local b, e = getactualtext(unicode)
                        local w = character.width or 0
                        local s = #colorlist
                        local n = 1
                        local t = {
                            { "special", "pdf:direct: q " .. b }
                        }
                        for i=1,s do
                            local entry = colorlist[i]
                            n = n + 1 t[n] = colorvalues[entry.class]
                            n = n + 1 t[n] = { "char", entry.slot }
                            if s > 1 and i < s and w ~= 0 then
                                n = n + 1 t[n] = { "right", -w }
                            end
                        end
                        n = n + 1 t[n] = { "special", "pdf:direct:" .. e .. " Q" }
                        character.commands = t
                    end
                end
            end
        end
    end
end

fonts.handlers.otf.features.register {
    name         = "colr",
    description  = "color glyphs",
    manipulators = {
        base = initializecolr,
        node = initializecolr,
    }
}

local otfsvg   = otf.svg or { }
otf.svg        = otfsvg
otf.svgenabled = true

do

    local nofstreams = 0

 -- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ]
 -- local f_getstream = formatters[ [[svg-glyph-%05i]] ]

 -- function otfsvg.storepdfdata(pdf)
 --     nofstreams = nofstreams + 1
 --     storepdfdata = function(pdf)
 --         nofstreams = nofstreams + 1
 --         return f_setstream(nofstreams,pdf), f_getstream(nofstreams)
 --     end
 -- end

    local f_name = formatters[ [[svg-glyph-%05i]] ]
    local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]

    local cache = { }

    function otfsvg.storepdfdata(pdf)
        nofstreams = nofstreams + 1
        local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
        cache[n] = o -- we need to keep in mem
        return nil, f_used(n), nil
    end

    if context then

        local storepdfdata = otfsvg.storepdfdata
        local initialized  = false

        function otfsvg.storepdfdata(pdf)
            if not initialized then
                if resolvers.setmemstream then
                    local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
                    local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ]
                    local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
                    storepdfdata = function(pdf)
                        nofstreams = nofstreams + 1
                        return
                            f_setstream(nofstreams,pdf),
                            f_getstream(nofstreams),
                            f_nilstream(nofstreams)
                    end
                    otfsvg.storepdfdata = storepdfdata
                end
                initialized = true
            end
            return storepdfdata(pdf)
        end

    end

end

if context and xml.convert then

    local report_svg = logs.reporter("fonts","svg conversion")

    local xmlconvert = xml.convert
    local xmlfirst   = xml.first
    local loaddata   = io.loaddata
    local savedata   = io.savedata
    local remove     = os.remove

 -- function otfsvg.topdf(svgshapes)
 --     local svgfile   = "temp-otf-svg-shape.svg"
 --     local pdffile   = "temp-otf-svg-shape.pdf"
 --     local command   = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
 --     local testrun   = false
 --     local pdfshapes = { }
 --     local nofshapes = #svgshapes
 --     report_svg("processing %i svg containers",nofshapes)
 --     statistics.starttiming()
 --     for i=1,nofshapes do
 --         local entry = svgshapes[i]
 --         for j=entry.first,entry.last do
 --             local svg  = xmlconvert(entry.data)
 --             local data = xmlfirst(svg,"/svg[@id='glyph"..j.."']")
 --             savedata(svgfile,tostring(data))
 --             report_svg("processing svg shape of glyph %i in container %i",j,i)
 --             os.execute(command)
 --             pdfshapes[j] = loaddata(pdffile)
 --         end
 --         if testrun and i > testrun then
 --             report_svg("quiting test run")
 --             break
 --         end
 --     end
 --     remove(svgfile)
 --     statistics.stoptiming()
 --     report_svg("conversion time: %0.3f",statistics.elapsedtime())
 --     return pdfshapes
 -- end

    function otfsvg.topdf(svgshapes)
        local inkscape  = io.popen("inkscape --shell 2>&1","w")
        local pdfshapes = { }
        local nofshapes = #svgshapes
        local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
        local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
        local f_convert = formatters["%s --export-pdf=%s\n"]
        report_svg("processing %i svg containers",nofshapes)
        statistics.starttiming()
        for i=1,nofshapes do
            local entry = svgshapes[i]
            for j=entry.first,entry.last do
                local svg  = xmlconvert(entry.data)
                local root = svg and xmlfirst(svg,"/svg[@id='glyph"..j.."']")
                local data = root and tostring(root)
                if data and data ~= "" then
                    local svgfile = f_svgfile(j)
                    local pdffile = f_pdffile(j)
                    savedata(svgfile,data)
                    inkscape:write(f_convert(svgfile,pdffile))
                    pdfshapes[j] = true
                end
            end
        end
        inkscape:write("quit\n")
     -- while inkscape:read("*a") do
     --     os.sleep(0.1)
     -- end
        inkscape:close()
        report_svg("processing %i pdf results",nofshapes)
        for i in next, pdfshapes do
            local svgfile = f_svgfile(i)
            local pdffile = f_pdffile(i)
            pdfshapes[i] = loaddata(pdffile)
            remove(svgfile)
            remove(pdffile)
        end
        statistics.stoptiming()
        report_svg("conversion time: %0.3f",statistics.elapsedtime())
        return pdfshapes
    end

else

    function otfsvg.topdf(svgshapes)
        local svgfile   = "temp-otf-svg-shape.svg"
        local pdffile   = "temp-otf-svg-shape.pdf"
        local command   = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
        local pdfshapes = { }
        local nofshapes = #svgshapes
        texio.write(formatters["[converting %i svg glyphs to pdf using command %q : "](nofshapes,command))
        for i=1,nofshapes do
            local entry = svgshapes[i]
            for j=entry.first,entry.last do
                -- cross our fingers .. some, day i will filter
                texio.write(formatters["%i "](j))
                io.savedata(svgfile,tostring(entry.data))
                os.execute(command)
                pdfshapes[j] = io.loaddata(pdffile)
            end
        end
        os.remove(svgfile)
        texio.write("done]")
        return pdfshapes
    end

end

local function initializesvg(tfmdata,kind,value) -- hm, always value
    if value and otf.svgenabled then
        local characters   = tfmdata.characters
        local descriptions = tfmdata.descriptions
        local properties   = tfmdata.properties
        --
        local svg       = properties.svg
        local hash      = svg and svg.hash
        local timestamp = svg and svg.timestamp
        if not hash then
            return
        end
        --
        local pdffile   = containers.read(otf.pdfcache,hash)
        local pdfshapes = pdffile and pdffile.pdfshapes
        if not pdfshapes or pdffile.timestamp ~= timestamp then
            local svgfile   = containers.read(otf.svgcache,hash)
            local svgshapes = svgfile and svgfile.svgshapes
            pdfshapes = svgshapes and otfsvg.topdf(svgshapes) or { }
            containers.write(otf.pdfcache, hash, {
                pdfshapes = pdfshapes,
                timestamp = timestamp,
            })
        end
        if not pdfshapes or not next(pdfshapes) then
            return
        end
        --
        properties.virtualized = true
        tfmdata.fonts = {
            { id = 0 }
        }
        --
        local getactualtext = otf.getactualtext
        local storepdfdata  = otfsvg.storepdfdata
        --
        local nop = { "nop" }
        --
        for unicode, character in next, characters do
            local index = character.index
            if index then
                local pdf = pdfshapes[index]
                if pdf then
                    local setcode, name, nilcode = storepdfdata(pdf)
                    if name then
                        local bt, et = getactualtext(unicode)
                        local wd = character.width  or 0
                        local ht = character.height or 0
                        local dp = character.depth  or 0
                        character.commands = {
                            { "special", "pdf:direct:" .. bt },
                            { "down", dp },
                            setcode and { "lua", setcode } or nop,
                            { "image", { filename = name, width = wd, height = ht, depth = dp } },
                            nilcode and { "lua", nilcode } or nop,
                            { "special", "pdf:direct:" .. et },
                        }
                        character.svg = true
                    end
                end
            end
        end
    end
end

fonts.handlers.otf.features.register {
    name         = "svg",
    description  = "svg glyphs",
    manipulators = {
        base = initializesvg,
        node = initializesvg,
    }
}
