if not modules then modules = { } end modules ['mtx-server-ctx-fonttest'] = { version = 1.001, comment = "Font Feature Tester", author = "Hans Hagen", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- probably too much but who cares dofile(resolvers.findfile("trac-lmx.lua","tex")) dofile(resolvers.findfile("font-ini.lua","tex")) dofile(resolvers.findfile("font-con.lua","tex")) dofile(resolvers.findfile("font-oti.lua","tex")) dofile(resolvers.findfile("font-otf.lua","tex")) dofile(resolvers.findfile("font-otp.lua","tex")) dofile(resolvers.findfile("font-ott.lua","tex")) dofile(resolvers.findfile("font-syn.lua","tex")) dofile(resolvers.findfile("font-mis.lua","tex")) local format, gsub, concat, match, find = string.format, string.gsub, table.concat, string.match, string.find local report = logs.reporter("ctx-fonttest") local sample_line = "This is a sample line!" local tempname = "mtx-server-ctx-fonttest-temp" local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") local basename = "mtx-server-ctx-fonttest-data.lua" local basepath = temppath local remove_suffixes = { "tex", "pdf", "log" } local what_options = { "trace", "basemode" } for i=1,#remove_suffixes do os.remove(file.join(temppath,file.addsuffix(tempname,remove_suffixes[i]))) end local process_templates = { } process_templates.default = [[ \starttext \setupdirections[bidi=global] \definefontfeature[sample][analyze=yes,%s] \definedfont[name:%s*sample] \startTEXpage[offset=3pt] \detokenize{%s} \stopTEXpage \stoptext ]] process_templates.cache = [[ \starttext \definedfont[name:%s] \startTEXpage[offset=3pt] cached: \detokenize{%s} \stopTEXpage \stoptext ]] process_templates.trace = [[ \usemodule[fnt-20] \definefontfeature[sample][%s] \setupcolors[state=start] \setupdirections[bidi=global] \setvariables [otftracker] [title=Test Run, font=name:%s, direction=0, features=sample, sample={‍\detokenize{%s}}] ]] local javascripts = [[ function selected_radio(name) { var form = document.forms["main-form"] ; var script = form.elements[name] ; if (script) { var n = script.length ; if (n) { for (var i=0; i safe name     family name     style-variant-weight-width     font name     weight     filename ]] local template_d = [[ %s     %s     %s-%s-%s-%s     %s     %s     %s ]] local function select_font() local t = fonts.names.list(".*",false,true) if t then local listoffonts = { } listoffonts[#listoffonts+1] = "" listoffonts[#listoffonts+1] = template_h for k, v in table.sortedhash(t) do local kind = v.format if kind == "otf" or kind == "ttf" or kind == "ttc" then local fontname = v.fontname listoffonts[#listoffonts+1] = format(template_d, fontname, fontname, v.familyname or "", t.variant or "normal", t.weight or "normal", t.width or "normal", t.style or "normal", v.rawname or fontname, v.fontweight or "", v.filename or "" ) end end listoffonts[#listoffonts+1] = "
" return concat(listoffonts,"\n") end return "no fonts" end local edit_template = [[

name:    title: 

scripts: %s

languages: %s

features: %s

options: %s ]] -- local result_template = [[



results: tex file pdf file

]] scripts.webserver.registerpath(temppath) local function get_specification(name) return fonts.names.resolvedspecification(name or "") end local function edit_font(currentfont,detail,tempname) report("entering edit mode for '%s'",currentfont) local specification = get_specification(currentfont) if specification then local htmldata = showfeatures(specification.filename) if htmldata then local features, languages, scripts, options = { }, { }, { }, { } local sorted = table.sortedkeys(htmldata.scripts) for k=1,#sorted do local v = sorted[k] local s = fonts.handlers.otf.tables.scripts[v] or v if detail and v == detail.script then scripts[#scripts+1] = format(" %s",s,v,v,v,v) else scripts[#scripts+1] = format(" %s",s,v,v,v,v) end end local sorted = table.sortedkeys(htmldata.languages) for k=1,#sorted do local v = sorted[k] local l = fonts.handlers.otf.tables.languages[v] or v if detail and v == detail.language then languages[#languages+1] = format(" %s",l,v,v,v,v) else languages[#languages+1] = format(" %s",l,v,v,v,v) end end local sorted = table.sortedkeys(htmldata.features) for k=1,#sorted do local v = sorted[k] local f = fonts.handlers.otf.tables.features[v] or v if detail and detail["f-"..v] then features[#features+1] = format(" %s",f,v,v,v,v) else features[#features+1] = format(" %s",f,v,v,v,v) end end for k=1,#what_options do local v = what_options[k] if detail and detail["o-"..v] then options[#options+1] = format(" %s",v,v,v) else options[#options+1] = format(" %s",v,v,v) end end local e = format(edit_template, (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "", concat(scripts," "),concat(languages," "),concat(features," "),concat(options," ")) if tempname then local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex") local r = format(result_template,pdffile,texfile,pdffile) return e .. r, htmldata.javascript or "" else return e, htmldata.javascript or "" end else return "error, nothing set up yet" end else return "error, no info about font" end end local function process_font(currentfont,detail) -- maybe just fontname local features = { "mode=node", format("language=%s",detail.language or "dflt"), format("script=%s",detail.script or "dflt"), } for k,v in next, detail do local f = match(k,"^f%-(.*)$") if f then features[#features+1] = format("%s=yes",f) end end local variant = process_templates.default if detail["o-trace"] then variant = process_templates.trace end local sample = string.strip(detail.sampletext or "") if sample == "" then sample = sample_line end report("sample text: %s",sample) dir.mkdirs(temppath) local fullname = file.join(temppath,file.addsuffix(tempname,"tex")) local data = format(variant,concat(features,","),currentfont,sample) local command = format("mtxrun --path=%q --script context --once --batchmode %q",temppath,tempname) report("filename: %s",fullname) report("command: %s",command) io.savedata(fullname,data) os.execute(command) return edit_font(currentfont,detail,tempname) end local tex_template = [[

%s
]] local function show_source(currentfont,detail) if tempname and tempname ~= "" then local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,"tex"))) or "no source yet" return format(tex_template,data) else return "no source file" end end local function show_log(currentfont,detail) if tempname and tempname ~= "" then local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,'log'))) or "no log file yet" data = gsub(data,"[%s%%]*begin of optionfile.-end of optionfile[%s%%]*","\n") return format(tex_template,data) else return "no log file" end end local function show_font(currentfont,detail) local specification = get_specification(currentfont) local features = fonts.helpers.getfeatures(specification.filename) local result = { } result[#result+1] = format("

names

",what) result[#result+1] = "" result[#result+1] = format("",currentfont) result[#result+1] = format("",specification.fontname or "-") result[#result+1] = format("",specification.fontfile or "-") result[#result+1] = format("",specification.familyname or "-") result[#result+1] = format("",specification.fontweight or "-") result[#result+1] = format("",specification.format or "-") result[#result+1] = format("",specification.fullname or "-") result[#result+1] = format("",specification.subfamily or "-") result[#result+1] = format("",specification.rawname or "-") result[#result+1] = format("",specification.designsize or "-") result[#result+1] = format("",specification.minsize or "-") result[#result+1] = format("",specification.maxsize or "-") result[#result+1] = format("",specification.style ~= "" and specification.style or "normal") result[#result+1] = format("",specification.variant ~= "" and specification.variant or "normal") result[#result+1] = format("",specification.weight ~= "" and specification.weight or "normal") result[#result+1] = format("",specification.width ~= "" and specification.width or "normal") result[#result+1] = "
fontname: %s
fullname: %s
filename: %s
familyname: %s
fontweight: %s
format: %s
fullname: %s
subfamily: %s
rawname: %s
designsize: %s
minimumsize:%s
maximumsize:%s
style: %s
variant: %s
weight: %s
width: %s
" if features then for what, v in table.sortedhash(features) do local data = features[what] if data and next(data) then result[#result+1] = format("

%s features

",what) result[#result+1] = "" result[#result+1] = "" for f,ff in table.sortedhash(data) do local done = false for s, ss in table.sortedhash(ff) do if s == "*" then s = "all" end if ss ["*"] then ss["*"] = nil ss.all = true end if done then f = "" else done = true end local title = fonts.handlers.otf.tables.features[f] or "" result[#result+1] = format("",title,f,s,concat(table.sortedkeys(ss)," ")) end end result[#result+1] = "
featuretag script languages 
%s  %s  %s  %s  
" end end else result[#result+1] = "

This font has no features." end return concat(result,"\n") end local info_template = [[

version   : %s
comment   : %s
author    : %s
copyright : %s

maillist  : ntg-context at ntg.nl
webpage   : www.pragma-ade.nl
wiki      : contextgarden.net
]] local function info_about() local m = modules ['mtx-server-ctx-fonttest'] return format(info_template,m.version,m.comment,m.author,m.copyright) end local save_template = [[ the current setup has been saved:

name  %s
title  %s
font  %s
script  %s
language  %s
features  %s
options  %s
sampletext %s
]] local function loadbase() local datafile = file.join(basepath,basename) local storage = io.loaddata(datafile) or "" if storage == "" then storage = { } else report("loading '%s'",datafile) storage = loadstring(storage) storage = (storage and storage()) or { } end return storage end local function loadstored(detail,currentfont,name) local storage = loadbase() storage = storage and storage[name] if storage then currentfont = storage.font detail.script = storage.script or detail.script detail.language = storage.language or detail.language detail.title = storage.title or detail.title detail.sampletext = storage.text or detail.sampletext detail.name = name or "no name" for k,v in next, storage.features do detail["f-"..k] = v end for k,v in next, storage.options do detail["o-"..k] = v end end detail.loadname = nil return detail, currentfont end local function savebase(storage,name) local datafile = file.join(basepath,basename) report("saving '%s' in '%s'",name or "data",datafile) io.savedata(datafile,table.serialize(storage,true)) end local function deletestored(detail,currentfont,name) local storage = loadbase() if storage and name and storage[name] then report("deleting '%s' from base",name) storage[name] = nil savebase(storage) end detail.deletename = nil return detail, "" end local function save_font(currentfont,detail) local specification = get_specification(currentfont) local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, "" if detail then local htmldata = showfeatures(specification.filename) script = detail.script or script language = detail.language or language text = string.strip(detail.sampletext or text) name = string.strip(detail.name or name) title = string.strip(detail.title or title) for k,v in next, htmldata.features do if detail["f-"..k] then features[k] = true end end for k=1,#what_options do local v = what_options[k] if detail["o-"..v] then options[k] = true end end end if name == "" then name = "no name" end local storage = loadbase() storage[name] = { font = currentfont, title = title, script = script, language = language, features = features, options = options, text = text, } savebase(storage,name) return format(save_template,name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text) end local function load_font(currentfont) local datafile = file.join(basepath,basename) local storage = loadbase(datafile) local result = {} result[#result+1] = format("del name font fontname script language features title sampletext ") for k,v in table.sortedhash(storage) do local fontname, fontfile = get_specification(v.font) result[#result+1] = format("x %s %s %s %s %s %s %s %s ", k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "") end if #result == 1 then return "nothing saved yet" else return format("%s
",concat(result,"\n")) end end local function reset_font(currentfont) return edit_font(currentfont) end local extras_template = [[ remake font database (take some time)

]] local function do_extras(detail,currentfont,extra) return extras_template end local extras = { } local function do_extra(detail,currentfont,extra) local e = extras[extra] if e then e(detail,currentfont,extra) end return do_extras(detail,currentfont,extra) end function extras.reload() local command = "mtxrun --script font --reload" report("run command: %s",command) os.execute(command) return do_extras() end local status_template = [[ ]] local variables = { ['color-background-one'] = lmx.get('color-background-green'), ['color-background-two'] = lmx.get('color-background-blue'), ['title'] = 'ConTeXt Font Tester', ['formaction'] = "mtx-server-ctx-fonttest.lua", } function doit(configuration,filename,hashed) local start = os.clock() local detail = url.query(hashed.query or "") local currentfont = detail.currentfont local action = detail.action local selection = detail.selection local loadname = detail.loadname local deletename = detail.deletename local extra = detail.extra if loadname and loadname ~= "" then detail, currentfont = loadstored(detail,currentfont,loadname) action = "process" elseif deletename and deletename ~= "" then detail, currentfont = deletestored(detail,currentfont,deletename) action = "load" elseif selection and selection ~= "" then currentfont = selection elseif extra and extra ~= "" then do_extra(detail,currentfont,extra) action = "extras" end local fontname, fontfile = get_specification(currentfont) if fontfile then variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) else variables.title = 'ConTeXt Font Tester' end -- lua table and adapt local buttons = { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} local menu = { } for i=1,#buttons do local button = buttons[i] menu[#menu+1] = format("",button,button) end variables.menu = concat(menu," ") variables.status = format(status_template,currentfont or "") variables.maintext = "" variables.javascriptdata = "" variables.javascripts = "" variables.javascriptinit = "" report("action: %s",action or "no action") local result if action == "select" then variables.maintext = select_font() elseif action == "info" then variables.maintext = info_about() elseif action == "extras" then variables.maintext = do_extras() elseif currentfont and currentfont ~= "" then if action == "save" then variables.maintext = save_font(currentfont,detail) elseif action == "load" then variables.maintext = load_font(currentfont,detail) elseif action == "source" then variables.maintext = show_source(currentfont,detail) elseif action == "log" then variables.maintext = show_log(currentfont,detail) elseif action == "features" then variables.maintext = show_font(currentfont,detail) else local e, s if action == "process" then e, s = process_font(currentfont,detail) elseif action == "reset" then e, s = reset_font(currentfont) elseif action == "edit" then e, s = edit_font(currentfont,detail) else e, s = process_font(currentfont,detail) end variables.maintext = e variables.javascriptdata = s variables.javascripts = javascripts variables.javascriptinit = "check_form()" end else variables.maintext = select_font() end result = { content = lmx.convert('context-fonttest.lmx',false,variables) } report("time spent on page: %0.03f seconds",os.clock()-start) return result end return doit, true --~ make_lmx_page("test")