summaryrefslogtreecommitdiff
path: root/tex/context/modules/mkiv/s-fonts-tables.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/modules/mkiv/s-fonts-tables.lua')
-rw-r--r--tex/context/modules/mkiv/s-fonts-tables.lua655
1 files changed, 534 insertions, 121 deletions
diff --git a/tex/context/modules/mkiv/s-fonts-tables.lua b/tex/context/modules/mkiv/s-fonts-tables.lua
index c32f4628c..33cbc924c 100644
--- a/tex/context/modules/mkiv/s-fonts-tables.lua
+++ b/tex/context/modules/mkiv/s-fonts-tables.lua
@@ -6,18 +6,45 @@ if not modules then modules = { } end modules ['s-fonts-tables'] = {
license = "see context related readme files"
}
-moduledata.fonts = moduledata.fonts or { }
-moduledata.fonts.tables = moduledata.fonts.tables or { }
-
-local setmetatableindex = table.setmetatableindex
-local sortedhash = table.sortedhash
-local sortedkeys = table.sortedkeys
-local format = string.format
-local concat = table.concat
-
-local tabletracers = moduledata.fonts.tables
-
-local context = context
+moduledata.fonts = moduledata.fonts or { }
+moduledata.fonts.tables = moduledata.fonts.tables or { }
+
+local setmetatableindex = table.setmetatableindex
+local sortedhash = table.sortedhash
+local sortedkeys = table.sortedkeys
+local concat = table.concat
+local insert = table.insert
+local remove = table.remove
+local formatters = string.formatters
+
+local tabletracers = moduledata.fonts.tables
+
+local new_glyph = nodes.pool.glyph
+local copy_node = nodes.copy
+local setlink = nodes.setlink
+local hpack = nodes.hpack
+local applyvisuals = nodes.applyvisuals
+
+local handle_positions = fonts.handlers.otf.datasetpositionprocessor
+local handle_injections = nodes.injections.handler
+
+local context = context
+local ctx_sequence = context.formatted.sequence
+local ctx_char = context.char
+local ctx_setfontid = context.setfontid
+local ctx_type = context.formatted.type
+local ctx_dontleavehmode = context.dontleavehmode
+local ctx_startPair = context.startPair
+local ctx_stopPair = context.stopPair
+local ctx_startSingle = context.startSingle
+local ctx_stopSingle = context.stopSingle
+local ctx_startSingleKern = context.startSingleKern
+local ctx_stopSingleKern = context.stopSingleKern
+local ctx_startPairKern = context.startPairKern
+local ctx_stopPairKern = context.stopPairKern
+
+local ctx_NC = context.NC
+local ctx_NR = context.NR
local digits = {
dflt = {
@@ -106,53 +133,73 @@ setmetatableindex(digits.dflt, function(t,k) return rawget(t,"dflt") end)
setmetatableindex(symbols.dflt, function(t,k) return rawget(t,"dflt") end)
setmetatableindex(punctuation.dflt, function(t,k) return rawget(t,"dflt") end)
-local function typesettable(t,keys,synonyms,nesting,prefix)
- if t then
+-- scaled boolean string scale string float cardinal
+
+local function checked(specification)
+ specification = interfaces.checkedspecification(specification)
+ local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
+ local tfmdata = fonts.hashes.identifiers[id]
+ local resources = tfmdata.resources
+ return tfmdata, id, resources
+end
+
+local function nothing()
+ context("no entries")
+ context.par()
+end
+
+local function typesettable(t,keys,synonyms,nesting,prefix,depth)
+ if t and next(keys) then
if not prefix then
context.starttabulate { "|Tl|Tl|Tl|" }
end
for k, v in sortedhash(keys) do
if k == "synonyms" then
elseif type(v) ~= "table" then
- context.NC()
+ ctx_NC()
if prefix then
context("%s.%s",prefix,k)
else
context(k)
end
- context.NC()
+ ctx_NC()
+ -- print(v)
local tk = t[k]
- if v == "boolean" then
+ if v == "<boolean>" then
context(tostring(tk or false))
elseif not tk then
context("<unset>")
- elseif v == "filename" then
+ elseif k == "filename" then
context(file.basename(tk))
- elseif v == "basepoints" then
- context("%sbp",tk)
- elseif v == "scaledpoints" then
+ -- elseif v == "basepoints" then
+ -- context("%sbp",tk)
+ elseif v == "<scaled>" then
context("%p",tk)
- elseif v == "table" then
+ elseif v == "<table>" then
context("<table>")
- else -- if v == "integerscale" then
+ else
context(tostring(tk))
end
- context.NC()
- local synonym = (not prefix and synonyms[k]) or (prefix and synonyms[format("%s.%s",prefix,k)])
+ ctx_NC()
+ local synonym = (not prefix and synonyms[k]) or (prefix and synonyms[formatters["%s.%s"](prefix,k)])
if synonym then
- context(format("(%s)",concat(synonym," ")))
+ context("(% t)",synonym)
end
- context.NC()
- context.NR()
+ ctx_NC()
+ ctx_NR()
elseif nesting == false then
context("<table>")
- else -- true or nil
- typesettable(t[k],v,synonyms,nesting,k)
+ elseif next(v) then
+ typesettable(t[k],v,synonyms,nesting,k,true)
end
end
if not prefix then
context.stoptabulate()
end
+ return
+ end
+ if not depth then
+ nothing()
end
end
@@ -175,51 +222,342 @@ end
tabletracers.typeset = typeset
-function tabletracers.showproperties(nesting)
- local tfmdata = fonts.hashes.identifiers[font.current()]
- typeset(tfmdata.properties,fonts.constructors.keys.properties,nesting)
+-- function tabletracers.showproperties(nesting)
+-- local tfmdata = fonts.hashes.identifiers[true]
+-- typeset(tfmdata.properties,fonts.constructors.keys.properties,nesting)
+-- end
+
+-- function tabletracers.showparameters(nesting)
+-- local tfmdata = fonts.hashes.identifiers[true]
+-- typeset(tfmdata.parameters,fonts.constructors.keys.parameters,nesting)
+-- end
+
+function tabletracers.showproperties(specification)
+ local tfmdata = checked(specification)
+ if tfmdata then
+ typeset(tfmdata.properties,fonts.constructors.keys.properties)
+ else
+ nothing()
+ end
+end
+
+function tabletracers.showparameters(specification)
+ local tfmdata = checked(specification)
+ if tfmdata then
+ typeset(tfmdata.parameters,fonts.constructors.keys.parameters)
+ else
+ nothing()
+ end
end
-function tabletracers.showparameters(nesting)
- local tfmdata = fonts.hashes.identifiers[font.current()]
- typeset(tfmdata.parameters,fonts.constructors.keys.parameters,nesting)
+local f_u = formatters["%U"]
+local f_p = formatters["%p"]
+
+local function morept(t)
+ local r = { }
+ for i=1,t do
+ r[i] = f_p(t[i])
+ end
+ return concat(r," ")
end
-function tabletracers.showpositionings()
- local tfmdata = fonts.hashes.resources[font.current()]
- local resources = tfmdata.resources
+local function noprefix(kind)
+ kind = string.gsub(kind,"^gpos_","")
+ kind = string.gsub(kind,"^gsub_","")
+ return kind
+end
+
+local function banner(index,i,format,kind,order,chain)
+ if chain then
+ ctx_sequence("sequence: %i, step %i, format: %s, kind: %s, features: % t, chain: %s",
+ index,i,format,noprefix(kind),order,noprefix(chain))
+ else
+ ctx_sequence("sequence: %i, step %i, format: %s, kind: %s, features: % t",
+ index,i,format,noprefix(kind),order)
+ end
+end
+
+function tabletracers.showpositionings(specification)
+
+ local tfmdata, fontid, resources = checked(specification)
+
if resources then
- local features = resources.features
- if features then
- local gpos = features.gpos
- if gpos and next(gpos) then
- context.starttabulate { "|Tl|Tl|Tlp|" }
- for feature, scripts in sortedhash(gpos) do
- for script, languages in sortedhash(scripts) do
- context.NC()
- context(feature)
- context.NC()
- context(script)
- context.NC()
- context(concat(sortedkeys(languages)," "))
- context.NC()
- context.NR()
+
+ local direction = "TLT"
+
+ local sequences = resources.sequences
+ local marks = resources.marks
+
+ if tonumber(direction) == -1 or direction == "TRT" then
+ direction = "TRT"
+ else
+ direction = "TLT"
+ end
+
+ local visuals = "fontkern,glyph,box"
+
+ local datasets = fonts.handlers.otf.dataset(tfmdata,fontid,0)
+
+ local function process(dataset,sequence,kind,order,chain)
+ local steps = sequence.steps
+ local order = sequence.order or order
+ local index = sequence.index
+ for i=1,#steps do
+ local step = steps[i]
+ local format = step.format
+ banner(index,i,format,kind,order,chain)
+ if kind == "gpos_pair" then
+ local format = step.format
+ if "kern" or format == "move" then
+ for first, seconds in sortedhash(step.coverage) do
+ local done = false
+ local zero = 0
+ for second, kern in sortedhash(seconds) do
+ if kern == 0 then
+ zero = zero + 1
+ else
+ if not done then
+ ctx_startPairKern()
+ end
+ local one = new_glyph(fontid,first)
+ local two = new_glyph(fontid,second)
+ local raw = setlink(copy_node(one),copy_node(two))
+ local pos = setlink(done and one or copy_node(one),copy_node(two))
+ pos, okay = handle_positions(pos,fontid,direction,dataset)
+ pos = handle_injections(pos)
+ applyvisuals(raw,visuals)
+ applyvisuals(pos,visuals)
+ pos = hpack(pos,"exact",nil,direction)
+ raw = hpack(raw,"exact",nil,direction)
+ ctx_NC() if not done then context(f_u(first)) end
+ ctx_NC() if not done then ctx_dontleavehmode() context(one) end
+ ctx_NC() context(f_u(second))
+ ctx_NC() ctx_dontleavehmode() context(two)
+ ctx_NC() context("%p",kern)
+ ctx_NC() ctx_dontleavehmode() context(raw)
+ ctx_NC() ctx_dontleavehmode() context(pos)
+ ctx_NC() ctx_NR()
+ done = true
+ end
+ end
+ if done then
+ ctx_stopPairKern()
+ end
+ if zero > 0 then
+ ctx_type("zero: %s",zero)
+ end
+ end
+ elseif format == "pair" then
+ for first, seconds in sortedhash(step.coverage) do
+ local done = false
+ local allnull = 0
+ local allzero = 0
+ local zeronull = 0
+ local nullzero = 0
+ for second, pair in sortedhash(seconds) do
+ local pfirst = pair[1]
+ local psecond = pair[2]
+ if not pfirst and not psecond then
+ allnull = allnull + 1
+ elseif pfirst == true and psecond == true then
+ allzero = allzero + 1
+ elseif pfirst == true and not psecond then
+ zeronull = zeronull + 1
+ elseif not pfirst and psecond == true then
+ nullzero = nullzero + 1
+ else
+ if pfirst == true then
+ pfirst = "all zero"
+ elseif pfirst then
+ pfirst = morept(pfirst)
+ else
+ pfirst = "no first"
+ end
+ if psecond == true then
+ psecond = "all zero"
+ elseif psecond then
+ psecond = morept(psecond)
+ else
+ psecond = "no second"
+ end
+ if not done then
+ ctx_startPair()
+ end
+ local one = new_glyph(fontid,first)
+ local two = new_glyph(fontid,second)
+ local raw = setlink(copy_node(one),copy_node(two))
+ local pos = setlink(done and one or copy_node(one),copy_node(two))
+ pos, okay = handle_positions(pos,fontid,direction,dataset)
+ pos = handle_injections(pos)
+ applyvisuals(raw,visuals)
+ applyvisuals(pos,visuals)
+ pos = hpack(pos,"exact",nil,direction)
+ raw = hpack(raw,"exact",nil,direction)
+ ctx_NC() if not done then context(f_u(first)) end
+ ctx_NC() if not done then ctx_dontleavehmode() context(one) end
+ ctx_NC() context(f_u(second))
+ ctx_NC() ctx_dontleavehmode() context(two)
+ ctx_NC() context(pfirst)
+ ctx_NC() context(psecond)
+ ctx_NC() ctx_dontleavehmode() context(raw)
+ ctx_NC() ctx_dontleavehmode() context(pos)
+ ctx_NC() ctx_NR()
+ done = true
+ end
+ end
+ if done then
+ ctx_stopPair()
+ end
+ if allnull > 0 or allzero > 0 or zeronull > 0 or nullzero > 0 then
+ ctx_type("both null: %s, both zero: %s, zero and null: %s, null and zero: %s",
+ allnull,allzero,zeronull,nullzero)
+ end
+ end
+ else
+ -- maybe
+ end
+ elseif kind == "gpos_single" then
+ local format = step.format
+ if format == "kern" or format == "move" then
+ local done = false
+ local zero = 0
+ for first, kern in sortedhash(step.coverage) do
+ if kern == 0 then
+ zero = zero + 1
+ else
+ if not done then
+ ctx_startSingleKern()
+ end
+ local one = new_glyph(fontid,first)
+ local raw = copy_node(one)
+ local pos = copy_node(one)
+ pos, okay = handle_positions(pos,fontid,direction,dataset)
+ pos = handle_injections(pos)
+ applyvisuals(raw,visuals)
+ applyvisuals(pos,visuals)
+ pos = hpack(pos,"exact",nil,direction)
+ raw = hpack(raw,"exact",nil,direction)
+ ctx_NC() context(f_u(first))
+ ctx_NC() ctx_dontleavehmode() context(one)
+ ctx_NC() context("%p",kern)
+ ctx_NC() ctx_dontleavehmode() context(raw)
+ ctx_NC() ctx_dontleavehmode() context(pos)
+ ctx_NC() ctx_NR()
+ done = true
+ end
+ end
+ if done then
+ ctx_stopSingleKern()
+ end
+ if zero > 0 then
+ ctx_type("zero: %i",zero)
+ end
+ elseif format == "single" then
+ local done = false
+ local zero = 0
+ local null = 0
+ for first, single in sortedhash(step.coverage) do
+ if single == false then
+ null = null + 1
+ elseif single == true then
+ zero = zero + 1
+ else
+ single = morept(single)
+ if not done then
+ ctx_startSingle()
+ end
+ local one = new_glyph(fontid,first)
+ local raw = copy_node(one)
+ local pos = copy_node(one)
+ pos, okay = handle_positions(pos,fontid,direction,dataset)
+ pos = handle_injections(pos)
+ applyvisuals(raw,visuals)
+ applyvisuals(pos,visuals)
+ raw = hpack(raw,"exact",nil,direction)
+ pos = hpack(pos,"exact",nil,direction)
+ ctx_NC() context(f_u(first))
+ ctx_NC() ctx_dontleavehmode() context(one)
+ ctx_NC() context(single)
+ ctx_NC() ctx_dontleavehmode() context(raw)
+ ctx_NC() ctx_dontleavehmode() context(pos)
+ ctx_NC() ctx_NR()
+ done = true
+ end
+ end
+ if done then
+ ctx_stopSingle()
+ end
+ if null > 0 then
+ if zero > 0 then
+ ctx_type("null: %i, zero: %i",null,zero)
+ else
+ ctx_type("null: %i",null)
+ end
+ else
+ if null > 0 then
+ ctx_type("both zero: %i",zero)
+ end
+ end
+ else
+ -- todo
end
end
- context.stoptabulate()
- else
- context("no entries")
- context.par()
end
end
+
+ local done = false
+
+ for d=1,#datasets do
+ local dataset = datasets[d]
+ local sequence = dataset[3]
+ local kind = sequence.type
+ if kind == "gpos_contextchain" or kind == "gpos_context" then
+ local steps = sequence.steps
+ for i=1,#steps do
+ local step = steps[i]
+ local rules = step.rules
+ if rules then
+ for i=1,#rules do
+ local rule = rules[i]
+ local lookups = rule.lookups
+ if lookups then
+ for i=1,#lookups do
+ local lookup = lookups[i]
+ if lookup then
+ local look = lookup[1]
+ local dnik = look.type
+ if dnik == "gpos_pair" or dnik == "gpos_single" then
+ process(dataset,look,dnik,sequence.order,kind)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ done = true
+ elseif kind == "gpos_pair" or kind == "gpos_single" then
+ process(dataset,sequence,kind)
+ done = true
+ end
+ end
+
+ if done then
+ return
+ end
+
end
+
+ nothing()
+
end
local dynamics = true
-function tabletracers.showsubstitutions()
- local tfmdata = fonts.hashes.identifiers[font.current()]
- local resources = tfmdata.resources
+function tabletracers.showsubstitutions(specification)
+
+ local tfmdata, fontid, resources = checked(specification)
+
if resources then
local features = resources.features
if features then
@@ -229,8 +567,8 @@ function tabletracers.showsubstitutions()
for feature, scripts in sortedhash(gsub) do
for script, languages in sortedhash(scripts) do
for language in sortedhash(languages) do
- local tag = format("dummy-%s-%s-%s",feature,script,language)
- local fnt = format("file:%s*%s",file.basename(tfmdata.properties.filename),tag)
+ local tag = formatters["dummy-%s-%s-%s"](feature,script,language)
+ local fnt = formatters["file:%s*%s"](file.basename(tfmdata.properties.filename),tag)
context.definefontfeature (
{ tag },
{
@@ -259,13 +597,13 @@ function tabletracers.showsubstitutions()
local data = makes_sense[i]
local script = data.script
local language = data.language
- context.NC()
+ ctx_NC()
context(data.feature)
- context.NC()
+ ctx_NC()
context(script)
- context.NC()
+ ctx_NC()
context(language)
- context.NC()
+ ctx_NC()
if not dynamics then
context.startfont { data.fontname }
else
@@ -279,85 +617,160 @@ function tabletracers.showsubstitutions()
if not dynamics then
context.stopfont()
end
- context.NC()
- context.NR()
+ ctx_NC()
+ ctx_NR()
end
context.stoptabulate()
- else
- context("no entries")
- context.par()
+ return
end
end
end
end
+
+ nothing()
+
end
-function tabletracers.showunicodevariants()
+function tabletracers.showunicodevariants(specification)
+
+ local tfmdata, fontid, resources = checked(specification)
- local variants = fonts.hashes.variants[true]
+ if resources then
- if variants then
- context.starttabulate { "|c|c|c|c|c|c|c|" }
- for selector, unicodes in sortedhash(variants) do
- local done = false
- for unicode, variant in sortedhash(unicodes) do
- context.NC()
- if not done then
- context("%U",selector)
- done = true
+ local variants = fonts.hashes.variants[fontid]
+
+ if variants then
+ context.starttabulate { "|c|c|c|c|c|c|c|" }
+ for selector, unicodes in sortedhash(variants) do
+ local done = false
+ for unicode, variant in sortedhash(unicodes) do
+ ctx_NC()
+ if not done then
+ context("%U",selector)
+ done = true
+ end
+ ctx_NC()
+ context("%U",unicode)
+ ctx_NC()
+ context("%c",unicode)
+ ctx_NC()
+ context("%U",variant)
+ ctx_NC()
+ context("%c",variant)
+ ctx_NC()
+ context("%c%c",unicode,selector)
+ ctx_NC()
+ context.startoverlay()
+ context("{\\color[trace:r]{%c}}{\\color[trace:ds]{%c}}",unicode,variant)
+ context.stopoverlay()
+ ctx_NC()
+ ctx_NR()
end
- context.NC()
- context("%U",unicode)
- context.NC()
- context("%c",unicode)
- context.NC()
- context("%U",variant)
- context.NC()
- context("%c",variant)
- context.NC()
- context("%c%c",unicode,selector)
- context.NC()
- context.startoverlay()
- context("{\\color[trace:r]{%c}}{\\color[trace:ds]{%c}}",unicode,variant)
- context.stopoverlay()
- context.NC()
- context.NR()
end
+ context.stoptabulate()
+ return
end
- context.stoptabulate()
+
end
+ nothing()
+
end
-function tabletracers.showall(specification) -- not interfaced
- specification = interfaces.checkedspecification(specification)
- if specification.title then
- context.starttitle { title = specification.title }
+local function collectligatures(steps)
+
+ local series = { }
+ local stack = { }
+ local max = 0
+
+ local function make(tree)
+ for k, v in sortedhash(tree) do
+ if k == "ligature" then
+ local n = #stack
+ if n > max then
+ max = n
+ end
+ series[#series+1] = { v, unpack(stack) }
+ else
+ insert(stack,k)
+ make(v)
+ remove(stack)
+ end
+ end
end
- context.startsubject { title = "Properties" }
- tabletracers.showproperties()
- context.stopsubject()
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ make(coverage)
+ end
+ end
- context.startsubject { title = "Parameters" }
- tabletracers.showparameters()
- context.stopsubject()
+ return series, max
+end
- context.startsubject { title = "Positioning features" }
- tabletracers.showpositionings()
- context.stopsubject()
+local function banner(index,kind,order)
+ ctx_sequence("sequence: %i, kind: %s, features: % t",index,noprefix(kind),order)
+end
+
+function tabletracers.showligatures(specification)
- context.startsubject { title = "Substitution features" }
- tabletracers.showsubstitutions()
- context.stopsubject()
+ local tfmdata, fontid, resources = checked(specification)
- context.startsubject { title = "Unicode variants" }
- tabletracers.showunicodevariants()
- context.stopsubject()
+ if resources then
- if title then
- context.stoptitle()
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local sequences = resources.sequences
+ if sequences then
+ local done = true
+ for index=1,#sequences do
+ local sequence = sequences[index]
+ local kind = sequence.type
+ if kind == "gsub_ligature" then
+ local list, max = collectligatures(sequence.steps)
+ if #list > 0 then
+ banner(index,kind,sequence.order or { })
+ context.starttabulate { "|T|" .. string.rep("|",max) .. "|T|T|" }
+ for i=1,#list do
+ local s = list[i]
+ local n = #s
+ local u = s[1]
+ local c = characters[u]
+ local d = descriptions[u]
+ ctx_NC()
+ context("%U",u)
+ ctx_NC()
+ ctx_setfontid(fontid)
+ ctx_char(u)
+ ctx_NC()
+ ctx_setfontid(fontid)
+ for i=2,n do
+ ctx_char(s[i])
+ ctx_NC()
+ end
+ for i=n+1,max do
+ ctx_NC()
+ end
+ context(d.name)
+ ctx_NC()
+ context(c.tounicode)
+ ctx_NC()
+ ctx_NR()
+ end
+ context.stoptabulate()
+ done = true
+ end
+ end
+ end
+ if done then
+ return
+ end
+ end
end
+ nothing()
+
end