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

local next, type, tonumber = next, type, tonumber
local ceil = math.ceil

local fonts              = fonts
local utilities          = utilities

local helpers            = fonts.helpers
local prependcommands    = helpers.prependcommands
local charcommand        = helpers.commands.char
local rightcommand       = helpers.commands.right

local handlers           = fonts.handlers
local otf                = handlers.otf
local afm                = handlers.afm

local registerotffeature = otf.features.register
local registerafmfeature = afm.features.register

local settings_to_array  = utilities.parsers.settings_to_array
local settings_to_hash   = utilities.parsers.settings_to_hash
local gettexdimen        = tex.getdimen

-- For Wolfgang Schuster:
--
-- \definefontfeature[thisway][default][script=hang,language=zhs,dimensions={2,2,2}]
-- \definedfont[file:kozminpr6nregular*thisway]

local function initialize(tfmdata,key,value)
    if type(value) == "string" and value ~= "" then
        --
        local hash  = settings_to_hash(value)
        local array = settings_to_array(value)
        --
        local characters = tfmdata.characters
        local parameters = tfmdata.parameters
        local emwidth    = parameters.quad
        local exheight   = parameters.xheight
        local newwidth   = false
        local newheight  = false
        local newdepth   = false
        local newshift   = false
        local scaletoo   = hash.scale
        if hash.strut then
            newheight = gettexdimen("strutht")
            newdepth  = gettexdimen("strutdp")
        elseif hash.mono then
            newwidth  = emwidth
        elseif hash.halfmono then
            newwidth  = emwidth / 2
        else
            -- there are fonts out there with no x_height ...
            newwidth  = array[1]
            newheight = array[2]
            newdepth  = array[3]
            newshift  = array[4]
            local quad      = parameters.quad      or 0
            local ascender  = parameters.ascender  or 0
            local descender = parameters.descender or 0
            if newwidth  == "max" then
                newwidth = quad
            else
                newwidth = tonumber(newwidth)
                if newwidth then
                    newwidth = newwidth * emwidth
                end
            end
            if newheight == "max" then
                newheight = ascender
            else
                newheight = tonumber(newheight)
                if newheight then
                    newheight = newheight * exheight
                end
            end
            if newdepth == "max" then
                newdepth = descender
            else
                newdepth = tonumber(newdepth)
                if newdepth then
                    newdepth  = newdepth  * exheight
                end
            end
            if parameters.x_heigth == 0 then
                -- maybe a fourth parameter
                parameters.x_heigth = (ascender + descender) / 2
            end
        end
        -- todo: hshift too
        if newwidth or newheight or newdepth then
            for unicode, character in next, characters do
                local oldwidth  = character.width
                local oldheight = character.height
                local olddepth  = character.depth
                local width  = newwidth  or oldwidth  or 0
                local height = newheight or oldheight or 0
                local depth  = newdepth  or olddepth  or 0
                if oldwidth ~= width or oldheight ~= height or olddepth ~= depth then
                    character.width  = width
                 -- character.advance  = oldwidth
                    character.height = height
                    character.depth  = depth
                    if oldwidth ~= width then
                        -- todo: see below
--                         local commands = character.commands
--                         local hshift   = rightcommand[newshift or ((width - oldwidth) / 2)]
--                         if commands then
--                             character.commands = prependcommands (
--                                 commands,
--                                 hshift
--                             )
--                         else
--                             character.commands = {
--                                 hshift,
--                                 charcommand[unicode],
--                             }
--                         end
                    character.width   = newwidth
                    character.advance = oldwidth
if scaletoo then
    local extend = newwidth/oldwidth
    character.effect  = { extend = extend }
    character.xoffset = (newwidth - extend * oldwidth)/2
else
                    character.xoffset = (newwidth - oldwidth)/2
end
                    end
                end
            end
        end
    end
end

local specification = {
    name        = "dimensions",
    description = "force dimensions",
    manipulators = {
        base = initialize,
        node = initialize,
    }
}

registerotffeature(specification)
registerafmfeature(specification)

local function initialize(tfmdata,key,value)
    if value then
        local characters = tfmdata.characters
        local parameters = tfmdata.parameters
        local emwidth    = parameters.quad
        local factor     = parameters.size/655360
        local fixedwidth = (tonumber(value) or 1)*factor*655360
        parameters.space = 2*fixedwidth
     -- parameters.space = fixedwidth * ceil(parameters.space/fixedwidth)
        for unicode, character in next, characters do
            local oldwidth = character.width
            if oldwidth ~= 0 then
                local newwidth = false
                if oldwidth > fixedwidth then
                    newwidth = fixedwidth * ceil(oldwidth/fixedwidth)
                elseif oldwidth < fixedwidth then
                    newwidth = fixedwidth
                end
                if newwidth then
                    character.width   = newwidth
                    character.advance = oldwidth
                    character.xoffset = (newwidth - oldwidth)/2
                end
            end
        end
    end
end

local specification = {
    name        = "fixedwidth",
    description = "force fixed widths",
    manipulators = {
        base = initialize,
        node = initialize,
    }
}

registerotffeature(specification)
registerafmfeature(specification)

-- -- \definefontfeature[fixedarabic][arabic][zeromarks=yes,mset=yes]

local categories = characters.categories
local is_mark    = characters.is_mark

local well = false

local function getwell()
    local chardata = characters.data
    local markdata = { }
    local function crap(b)
        for i=b.first,b.last do
            local specials = chardata[i].specials
            if specials then
             -- local m = true
                if specials[2] == 0x20 then
                 -- for i=3,#specials do
                 --     local s = specials[i]
                 --     if not is_mark[categories[s]] then
                 --         m = false
                 --         break
                 --     end
                 -- end
                 -- if m then
                        markdata[i] = true
                 -- end
                end
            end
        end
    end
    crap(characters.blocks.arabicpresentationformsa)
    crap(characters.blocks.arabicpresentationformsb)
    return markdata
end

local function initialize(tfmdata,key,value)
    if value then
        local resources = tfmdata.resources
        if resources then
            local characters = tfmdata.characters
            local marks = resources.marks -- markclasses marksets
            if next(marks) then
                for k, v in next, marks do
                    local c = characters[v]
                    if c then
                        local w = v.width
                        if w ~= 0 then
                            c.advance = w
                            c.width   = 0
                        end
                    end
                end
            else
                if not well then
                    well = getwell()
                end
                for k in next, well do
                    local c = characters[k]
                    if c then
                        local w = c.width
                        if w ~= 0 then
                            c.advance = w
                            c.width   = 0
                        end
                    end
                end
                for k, v in next, characters do
                    local u = v.unicode
                    if type(u) == "table" then
                        for i=1,#u do
                            if is_mark[categories[u[i]]] then
                                local w = v.width
                                if w ~= 0 then
                                    v.advance = w
                                    v.width   = 0
                                    break
                                end
                            end
                        end
                    else
                        if is_mark[categories[u]] then
                            local w = v.width
                            if w ~= 0 then
                                v.advance = w
                                v.width   = 0
                            end
                        end
                    end
                end
            end
        end
    end
end

local specification = {
    name         = "zeromarks",
    description  = "zero width marks",
    manipulators = {
     -- base = initialize,
        node = initialize,
    }
}

registerotffeature(specification)
