if not modules then modules = { } end modules ['font-phb-imp-internal'] = {
    version   = 1.000, -- 2016.10.10,
    comment   = "companion to font-txt.mkiv",
    original  = "derived from font-phb-imp-library",
    author    = "Hans Hagen",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files",
}

-- The hb library comes in versions and the one I tested in 2016 was part of the inkscape
-- suite. In principle one can have incompatibilities due to updates but that is the nature
-- of a library. When a library ie expected one has better use the system version, if only
-- to make sure that different programs behave the same.
--
-- The main reason for testing this approach was that when Idris was working on his fonts,
-- we wanted to know how different shapers deal with it and the hb command line program
-- could provide uniscribe output. For the context shaper uniscribe is the reference, also
-- because Idris started out with Volt a decade ago.
--
-- We treat the lib as a black box as it should be. At some point Kai Eigner made an ffi
-- binding and that one was adapted to the plugin approach of context. It saved me the
-- trouble of looking at source files to figure it all out. Below is the adapted code.
--
-- This is basically the ffi variant but with the hb function calls delegated to a simple
-- runtime library. That library was a side effect of playing a day with delayed loading
-- like ffi does in luametatex, which seems to work ok for what we call optional libraries
-- in lmtx. I didn't really test the next code well (and will probably do that when Idris
-- needs some comparison with uniscribe etc). There are nowadays probably other ways to do
-- this but this is what we had and so we can keep the test code that has been around for
-- a while (which is needed because some old articles need it.)
--
-- The following setup doesn't really fit into the way we set up internal libraries
-- but if isn't used in the same sense anyway so we stick to what we already had in
-- the ffi variant (also because it uses helpers here and we want to keep the client
-- variant too). We don't need to be generic as other macro packages follow a different
-- route.
--
-- Last time I checked "fiets" got no ligature with the "ot" shaper but it did get one
-- with the "uniscribe" shaper ... somewhat puzzling .. but "effe" worked okay. Maybe
-- there is some built-in heuristic interfering? When Idris an I tested fonts we had
-- similar differences with arabic so maybe we miss a point here.
--
-- native     font plugin > hb > string : fi-
--            font plugin > hb > text   : U+00066 U+00069 U+0002D
--            font plugin > hb > result : U+00066 U+00069 U+0002D
--
-- uniscribe  font plugin > hb > string : fi-
--            font plugin > hb > text   : U+00066 U+00069 U+0002D
--            font plugin > hb > result : U+0FB01 U+0002D
--
-- native     font plugin > hb > string : ets
--            font plugin > hb > text   : U+00065 U+00074 U+00073
--            font plugin > hb > result : U+00065 U+00074 U+00073
--
-- uniscribe  font plugin > hb > string : ets
--            font plugin > hb > text   : U+00065 U+00074 U+00073
--            font plugin > hb > result : U+00065 U+00074 U+00073
--
-- native     font plugin > hb > string : fiets
--            font plugin > hb > text   : U+00066 U+00069 U+00065 U+00074 U+00073
--            font plugin > hb > result : U+00066 U+00069 U+00065 U+00074 U+00073
--
-- uniscribe  font plugin > hb > string : fiets
--            font plugin > hb > text   : U+00066 U+00069 U+00065 U+00074 U+00073
--            font plugin > hb > result : U+0FB01 U+00065 U+00074 U+00073

-- In the meantime a single dll is not enough and we need some more which interferes with
-- the idea of a simple dll in the lib path ... too many dependencies now .. and having
-- some shared bin path is not what we want in tex so ...

local report = utilities.hb.report or print

local hblib  = optional and (optional.hb or optional.test)

if not hblib then
    report("no hblib found, you can try the ffi variant")
    return
end

local hb_initialize  = hblib.initialize
local hb_getversion  = hblib.getversion
local hb_getshapers  = hblib.getshapers
local hb_loadfont    = hblib.loadfont
local hb_shapestring = hblib.shapestring

if not hb_initialize then
    report("no functions in hblib found, you can try the ffi variant")
    return
end

local loaddata    = io.loaddata
local findlib     = resolvers.findlib
local concat      = table.concat
local utfchar     = utf.char
local packtoutf8  = utilities.hb.helpers.packtoutf8
local packtoutf32 = utilities.hb.helpers.packtoutf32
local report      = utilities.hb.report or print
local fontdata    = fonts.hashes.identifiers
local initialized = nil
local loaded      = { }
local shared      = { }
local libfile     = os.name == "windows" and "libharfbuzz-0" or "libharfbuzz"

local shapers = {
    native    = { "ot", "uniscribe", "fallback" },
    uniscribe = { "uniscribe", "ot", "fallback" },
 -- uniscribe = { "uniscribe", "fallback" }, -- stalls without fallback when no uniscribe present
    fallback  = { "fallback" },
}

----- mode = 8  -- now 32 bit crashes (random, needs checking, probably zero end of string issue)
local mode = 32 -- now 32 bit crashes (random, needs checking, probably zero end of string issue)

function utilities.hb.methods.internal(font,data,rlmode,text,leading,trailing)
    if initialized == nil then
        local filename = findlib(libfile)
        initialized = hb_initialize(filename)
        if initialized then
            report("using hb library version %a, supported shapers: %,t",hb_getversion(),hb_getshapers())
        else
            report("unable to locate hb library")
            initialize = false
        end
    end
    if initialized then
        local instance = loaded[font]
        if instance == nil then
            local tfmdata   = fontdata[font]
            local resources = tfmdata.resources
            local filename  = resources.filename
                  instance  = shared[filename]
            if instance == nil then
                local wholefont = loaddata(filename)
                if wholefont then
                    instance = hb_loadfont(font,wholefont)
                end
                if not instance then
                    instance = false
                end
                shared[filename] = instance
            end
            loaded[font] = instance
        end
        if instance then
            if mode ==32 then
                text = packtoutf32(text,leading,trailing)
            else
                text = packtoutf8(text,leading,trailing) -- doesn't work ok (no time not to figure it out)
            end
            local result = hb_shapestring (
                instance,
                data.script          or "dflt",
                data.language        or "dflt",
                rlmode < 0 and "rtl" or "ltr",
                shapers[data.shaper] or shapers.native,
                data.featureset      or { },
                text,
                rlmode < 0,
                mode
            )
         -- inspect(result)
            return result
        end
    end
end