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

-- generic [base|node] mode handler

if context then
    texio.write_nl("fatal error: this module is not for context")
    os.exit()
end

local fonts = fonts
local nodes = nodes

local nuts        = nodes.nuts -- context abstraction of direct nodes

local traverse_id = nuts.traverse_id
local flush_node  = nuts.flush_node

local glyph_code  = nodes.nodecodes.glyph
local disc_code   = nodes.nodecodes.disc

local tonode      = nuts.tonode
local tonut       = nuts.tonut

local getfont     = nuts.getfont
local getchar     = nuts.getchar
local getid       = nuts.getid
local getboth     = nuts.getboth
local getprev     = nuts.getprev
local getnext     = nuts.getnext
local getdisc     = nuts.getdisc
local setchar     = nuts.setchar
local setlink     = nuts.setlink
local setprev     = nuts.setprev

-- from now on we apply ligaturing and kerning here because it might interfere with complex
-- opentype discretionary handling where the base ligature pass expect some weird extra
-- pointers (which then confuse the tail slider that has some checking built in)

local n_ligaturing = node.ligaturing
local n_kerning    = node.kerning

local ligaturing   = nuts.ligaturing
local kerning      = nuts.kerning

local basemodepass = true

local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning = nil end
local function k_warning() texio.write_nl("warning: node.kerning called directly")    k_warning = nil end

function node.ligaturing(...)
    if basemodepass and l_warning then
        l_warning()
    end
    return n_ligaturing(...)
end

function node.kerning(...)
    if basemodepass and k_warning then
        k_warning()
    end
    return n_kerning(...)
end

function nodes.handlers.setbasemodepass(v)
    basemodepass = v
end

function nodes.handlers.nodepass(head)
    local fontdata = fonts.hashes.identifiers
    if fontdata then
        local nuthead   = tonut(head)
        local usedfonts = { }
        local basefonts = { }
        local prevfont  = nil
        local basefont  = nil
        local variants  = nil
        local redundant = nil
        for n in traverse_id(glyph_code,nuthead) do
            local font = getfont(n)
            if font ~= prevfont then
                if basefont then
                    basefont[2] = getprev(n)
                end
                prevfont = font
                local used = usedfonts[font]
                if not used then
                    local tfmdata = fontdata[font] --
                    if tfmdata then
                        local shared = tfmdata.shared -- we need to check shared, only when same features
                        if shared then
                            local processors = shared.processes
                            if processors and #processors > 0 then
                                usedfonts[font] = processors
                            elseif basemodepass then
                                basefont = { n, nil }
                                basefonts[#basefonts+1] = basefont
                            end
                        end
                        local resources = tfmdata.resources
                        variants = resources and resources.variants
                        variants = variants and next(variants) and variants or false
                    end
                else
                    local tfmdata = fontdata[prevfont]
                    if tfmdata then
                        local resources = tfmdata.resources
                        variants = resources and resources.variants
                        variants = variants and next(variants) and variants or false
                    end
                end
            end
            if variants then
                local char = getchar(n)
                if char >= 0xFE00 and (char <= 0xFE0F or (char >= 0xE0100 and char <= 0xE01EF)) then
                    local hash = variants[char]
                    if hash then
                        local p = getprev(n)
                        if p and getid(p) == glyph_code then
                            local variant = hash[getchar(p)]
                            if variant then
                                setchar(p,variant)
                            end
                        end
                    end
                    -- per generic user request we always remove selectors
                    if not redundant then
                        redundant = { n }
                    else
                        redundant[#redundant+1] = n
                    end
                end
            end
        end
        local nofbasefonts = #basefonts
        if redundant then
            for i=1,#redundant do
                local r = redundant[i]
                local p, n = getboth(r)
                if r == nuthead then
                    nuthead = n
                    setprev(n)
                else
                    setlink(p,n)
                end
                if nofbasefonts > 0 then
                    for i=1,nofbasefonts do
                        local bi = basefonts[i]
                        if r == bi[1] then
                            bi[1] = n
                        end
                        if r == bi[2] then
                            bi[2] = n
                        end
                    end
                end
                flush_node(r)
            end
        end
        for d in traverse_id(disc_code,nuthead) do
            local _, _, r = getdisc(d)
            if r then
                for n in traverse_id(glyph_code,r) do
                    local font = getfont(n)
                    if font ~= prevfont then
                        prevfont = font
                        local used = usedfonts[font]
                        if not used then
                            local tfmdata = fontdata[font] --
                            if tfmdata then
                                local shared = tfmdata.shared -- we need to check shared, only when same features
                                if shared then
                                    local processors = shared.processes
                                    if processors and #processors > 0 then
                                        usedfonts[font] = processors
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
        if next(usedfonts) then
            for font, processors in next, usedfonts do
                for i=1,#processors do
                    head = processors[i](head,font,0) or head
                end
            end
        end
        if basemodepass and nofbasefonts > 0 then
            for i=1,nofbasefonts do
                local range = basefonts[i]
                local start = range[1]
                local stop  = range[2]
                if start then
                    local front = nuthead == start
                    local prev, next
                    if stop then
                        next = getnext(stop)
                        start, stop = ligaturing(start,stop)
                        start, stop = kerning(start,stop)
                    else
                        prev  = getprev(start)
                        start = ligaturing(start)
                        start = kerning(start)
                    end
                    if prev then
                        setlink(prev,start)
                    end
                    if next then
                        setlink(stop,next)
                    end
                    if front and nuthead ~= start then
                        head = tonode(start)
                    end
                end
            end
        end
        return head, true
    else
        return head, false
    end
end

function nodes.handlers.basepass(head)
    if not basemodepass then
        head = n_ligaturing(head)
        head = n_kerning(head)
    end
    return head, true
end

local nodepass    = nodes.handlers.nodepass
local basepass    = nodes.handlers.basepass
local injectpass  = nodes.injections.handler
local protectpass = nodes.handlers.protectglyphs

function nodes.simple_font_handler(head)
    if head then
        head = nodepass(head)
        head = injectpass(head)
        if not basemodepass then
            head = basepass(head)
        end
        protectpass(head)
        return head, true
    else
        return head, false
    end
end
