summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-otp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-otp.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-otp.lua323
1 files changed, 239 insertions, 84 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-otp.lua b/Master/texmf-dist/tex/context/base/font-otp.lua
index f019ade7f48..8a37c5cdf5c 100644
--- a/Master/texmf-dist/tex/context/base/font-otp.lua
+++ b/Master/texmf-dist/tex/context/base/font-otp.lua
@@ -7,86 +7,236 @@ if not modules then modules = { } end modules ['font-otp'] = {
}
-- todo: pack math (but not that much to share)
+-- pitfall 5.2: hashed tables can suddenly become indexed with nil slots
local next, type = next, type
local sort, concat = table.sort, table.concat
+local sortedhash = table.sortedhash
+local trace_packing = false trackers.register("otf.packing", function(v) trace_packing = v end)
local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
local report_otf = logs.reporter("fonts","otf loading")
-- also used in other scripts so we need to check some tables:
fonts = fonts or { }
-fonts.handlers = fonts.handlers or { }
-local handlers = fonts.handlers
-handlers.otf = handlers.otf or { }
-local otf = handlers.otf
-otf.enhancers = otf.enhancers or { }
-local enhancers = otf.enhancers
-otf.glists = otf.glists or { "gsub", "gpos" }
-local glists = otf.glists
+
+local handlers = fonts.handlers or { }
+fonts.handlers = handlers
+
+local otf = handlers.otf or { }
+handlers.otf = otf
+
+local enhancers = otf.enhancers or { }
+otf.enhancers = enhancers
+
+local glists = otf.glists or { "gsub", "gpos" }
+otf.glists = glists
local criterium = 1
local threshold = 0
-local function tabstr(t)
- local s, n = { }, 0
+local function tabstr_normal(t)
+ local s = { }
+ local n = 0
for k, v in next, t do
n = n + 1
if type(v) == "table" then
- s[n] = k .. "={" .. tabstr(v) .. "}"
+ s[n] = k .. ">" .. tabstr_normal(v)
elseif v == true then
- s[n] = k .. "=true"
+ s[n] = k .. "+" -- "=true"
elseif v then
s[n] = k .. "=" .. v
else
- s[n] = k .. "=false"
+ s[n] = k .. "-" -- "=false"
end
end
- sort(s)
- return concat(s,",")
+ if n == 0 then
+ return ""
+ elseif n == 1 then
+ return s[1]
+ else
+ sort(s) -- costly but needed (occasional wrong hit otherwise)
+ return concat(s,",")
+ end
+end
+
+local function tabstr_flat(t)
+ local s = { }
+ local n = 0
+ for k, v in next, t do
+ n = n + 1
+ s[n] = k .. "=" .. v
+ end
+ if n == 0 then
+ return ""
+ elseif n == 1 then
+ return s[1]
+ else
+ sort(s) -- costly but needed (occasional wrong hit otherwise)
+ return concat(s,",")
+ end
end
+local function tabstr_mixed(t) -- indexed
+ local s = { }
+ local n = #t
+ if n == 0 then
+ return ""
+ elseif n == 1 then
+ local k = t[1]
+ if k == true then
+ return "++" -- we need to distinguish from "true"
+ elseif k == false then
+ return "--" -- we need to distinguish from "false"
+ else
+ return tostring(k) -- number or string
+ end
+ else
+ for i=1,n do
+ local k = t[i]
+ if k == true then
+ s[i] = "++" -- we need to distinguish from "true"
+ elseif k == false then
+ s[i] = "--" -- we need to distinguish from "false"
+ else
+ s[i] = k -- number or string
+ end
+ end
+ return concat(s,",")
+ end
+end
+
+local function tabstr_boolean(t)
+ local s = { }
+ local n = 0
+ for k, v in next, t do
+ n = n + 1
+ if v then
+ s[n] = k .. "+"
+ else
+ s[n] = k .. "-"
+ end
+ end
+ if n == 0 then
+ return ""
+ elseif n == 1 then
+ return s[1]
+ else
+ sort(s) -- costly but needed (occasional wrong hit otherwise)
+ return concat(s,",")
+ end
+end
+
+-- tabstr_boolean_x = tabstr_boolean
+
+-- tabstr_boolean = function(t)
+-- local a = tabstr_normal(t)
+-- local b = tabstr_boolean_x(t)
+-- print(a)
+-- print(b)
+-- return b
+-- end
+
local function packdata(data)
if data then
+ -- stripdata(data)
local h, t, c = { }, { }, { }
local hh, tt, cc = { }, { }, { }
local nt, ntt = 0, 0
- local function pack_1(v,indexed)
- -- v == table
- local tag = indexed and concat(v," ") or tabstr(v)
+ local function pack_normal(v)
+ local tag = tabstr_normal(v)
+ local ht = h[tag]
+ if ht then
+ c[ht] = c[ht] + 1
+ return ht
+ else
+ nt = nt + 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
+ end
+ end
+ local function pack_flat(v)
+ local tag = tabstr_flat(v)
local ht = h[tag]
- if not ht then
+ if ht then
+ c[ht] = c[ht] + 1
+ return ht
+ else
nt = nt + 1
- ht = nt
- t[ht] = v
- h[tag] = ht
- c[ht] = 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
+ end
+ end
+ local function pack_boolean(v)
+ local tag = tabstr_boolean(v)
+ local ht = h[tag]
+ if ht then
+ c[ht] = c[ht] + 1
+ return ht
else
+ nt = nt + 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
+ end
+ end
+ local function pack_indexed(v)
+ local tag = concat(v," ")
+ local ht = h[tag]
+ if ht then
c[ht] = c[ht] + 1
+ return ht
+ else
+ nt = nt + 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
+ end
+ end
+ local function pack_mixed(v)
+ local tag = tabstr_mixed(v)
+-- print(">>>",tag)
+ local ht = h[tag]
+ if ht then
+ c[ht] = c[ht] + 1
+ return ht
+ else
+ nt = nt + 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
end
- return ht
end
- local function pack_2(v,indexed)
+ local function pack_final(v)
-- v == number
if c[v] <= criterium then
return t[v]
else
-- compact hash
local hv = hh[v]
- if not hv then
+ if hv then
+ return hv
+ else
ntt = ntt + 1
- hv = ntt
- tt[hv] = t[v]
- hh[v] = hv
- cc[hv] = c[v]
+ tt[ntt] = t[v]
+ hh[v] = ntt
+ cc[ntt] = c[v]
+ return ntt
end
- return hv
end
end
local function success(stage,pass)
if nt == 0 then
- if trace_loading then
+ if trace_loading or trace_packing then
report_otf("pack quality: nothing to pack")
end
return false
@@ -114,35 +264,45 @@ local function packdata(data)
end
data.tables = tt
end
- if trace_loading then
+ if trace_loading or trace_packing then
report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", stage, pass, one+two+rest, one, two, rest, criterium)
end
return true
else
- if trace_loading then
+ if trace_loading or trace_packing then
report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", stage, pass, nt, threshold)
end
return false
end
end
+ local function packers(pass)
+ if pass == 1 then
+ return pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed
+ else
+ return pack_final, pack_final, pack_final, pack_final, pack_final
+ end
+ end
local resources = data.resources
local lookuptypes = resources.lookuptypes
for pass=1,2 do
- local pack = (pass == 1 and pack_1) or pack_2
+ if trace_packing then
+ report_otf("start packing: stage 1, pass %s",pass)
+ end
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
for unicode, description in next, data.descriptions do
local boundingbox = description.boundingbox
if boundingbox then
- description.boundingbox = pack(boundingbox,true)
+ description.boundingbox = pack_indexed(boundingbox)
end
local slookups = description.slookups
if slookups then
for tag, slookup in next, slookups do
local what = lookuptypes[tag]
if what == "pair" then
- local t = slookup[2] if t then slookup[2] = pack(t,true) end
- local t = slookup[3] if t then slookup[3] = pack(t,true) end
+ local t = slookup[2] if t then slookup[2] = pack_indexed(t) end
+ local t = slookup[3] if t then slookup[3] = pack_indexed(t) end
elseif what ~= "substitution" then
- slookups[tag] = pack(slookup)
+ slookups[tag] = pack_indexed(slookup) -- true is new
end
end
end
@@ -153,12 +313,12 @@ local function packdata(data)
if what == "pair" then
for i=1,#mlookup do
local lookup = mlookup[i]
- local t = lookup[2] if t then lookup[2] = pack(t,true) end
- local t = lookup[3] if t then lookup[3] = pack(t,true) end
+ local t = lookup[2] if t then lookup[2] = pack_indexed(t) end
+ local t = lookup[3] if t then lookup[3] = pack_indexed(t) end
end
elseif what ~= "substitution" then
for i=1,#mlookup do
- mlookup[i] = pack(mlookup[i]) -- true
+ mlookup[i] = pack_indexed(mlookup[i]) -- true is new
end
end
end
@@ -166,7 +326,7 @@ local function packdata(data)
local kerns = description.kerns
if kerns then
for tag, kern in next, kerns do
- kerns[tag] = pack(kern)
+ kerns[tag] = pack_flat(kern)
end
end
local math = description.math
@@ -174,7 +334,7 @@ local function packdata(data)
local kerns = math.kerns
if kerns then
for tag, kern in next, kerns do
- kerns[tag] = pack(kern)
+ kerns[tag] = pack_normal(kern)
end
end
end
@@ -184,12 +344,14 @@ local function packdata(data)
if what == "baselig" then
for _, a in next, anchor do
for k=1,#a do
- a[k] = pack(a[k])
+-- a[k] = pack_normal(a[k])
+ a[k] = pack_indexed(a[k])
end
end
else
for k, v in next, anchor do
- anchor[k] = pack(v)
+-- anchor[k] = pack_normal(v)
+ anchor[k] = pack_indexed(v)
end
end
end
@@ -200,38 +362,28 @@ local function packdata(data)
for _, lookup in next, lookups do
local rules = lookup.rules
if rules then
- for i=1,#rules do -- was next loop
+ for i=1,#rules do
local rule = rules[i]
---~ local r = rule.before if r then for i=1,#r do r[i] = pack(r[i],true) end end
---~ local r = rule.after if r then for i=1,#r do r[i] = pack(r[i],true) end end
---~ local r = rule.current if r then for i=1,#r do r[i] = pack(r[i],true) end end
---~ local r = rule.replacements if r then rule.replacements = pack(r, true) end
---~ local r = rule.fore if r then rule.fore = pack(r, true) end
---~ local r = rule.back if r then rule.back = pack(r, true) end
---~ local r = rule.names if r then rule.names = pack(r, true) end
---~ local r = rule.lookups if r then rule.lookups = pack(r) end
- local r = rule.before if r then for i=1,#r do r[i] = pack(r[i]) end end
- local r = rule.after if r then for i=1,#r do r[i] = pack(r[i]) end end
- local r = rule.current if r then for i=1,#r do r[i] = pack(r[i]) end end
- local r = rule.replacements if r then rule.replacements = pack(r) end
- -- local r = rule.fore if r then rule.fore = pack(r) end
- -- local r = rule.back if r then rule.back = pack(r) end
- -- local r = rule.names if r then rule.names = pack(r) end
- local r = rule.lookups if r then rule.lookups = pack(r) end
+ local r = rule.before if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
+ local r = rule.after if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
+ local r = rule.current if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
+ local r = rule.replacements if r then rule.replacements = pack_flat (r) end -- can have holes
+ -- local r = rule.lookups if r then rule.lookups = pack_mixed (r) end -- can have false
+ local r = rule.lookups if r then rule.lookups = pack_indexed(r) end -- can have ""
end
end
end
end
- local anchor_to_lookup = resources.anchor_to_lookup
+ local anchor_to_lookup = resources.anchor_to_lookup
if anchor_to_lookup then
for anchor, lookup in next, anchor_to_lookup do
- anchor_to_lookup[anchor] = pack(lookup)
+ anchor_to_lookup[anchor] = pack_normal(lookup)
end
end
local lookup_to_anchor = resources.lookup_to_anchor
if lookup_to_anchor then
for lookup, anchor in next, lookup_to_anchor do
- lookup_to_anchor[lookup] = pack(anchor)
+ lookup_to_anchor[lookup] = pack_normal(anchor)
end
end
local sequences = resources.sequences
@@ -239,16 +391,16 @@ local function packdata(data)
for feature, sequence in next, sequences do
local flags = sequence.flags
if flags then
- sequence.flags = pack(flags)
+ sequence.flags = pack_normal(flags)
end
local subtables = sequence.subtables
if subtables then
- sequence.subtables = pack(subtables)
+ sequence.subtables = pack_normal(subtables)
end
local features = sequence.features
if features then
for script, feature in next, features do
- features[script] = pack(feature)
+ features[script] = pack_normal(feature)
end
end
end
@@ -258,11 +410,11 @@ local function packdata(data)
for name, lookup in next, lookups do
local flags = lookup.flags
if flags then
- lookup.flags = pack(flags)
+ lookup.flags = pack_normal(flags)
end
local subtables = lookup.subtables
if subtables then
- lookup.subtables = pack(subtables)
+ lookup.subtables = pack_normal(subtables)
end
end
end
@@ -272,7 +424,7 @@ local function packdata(data)
local list = features[what]
if list then
for feature, spec in next, list do
- list[feature] = pack(spec)
+ list[feature] = pack_normal(spec)
end
end
end
@@ -283,27 +435,30 @@ local function packdata(data)
end
if nt > 0 then
for pass=1,2 do
- local pack = (pass == 1 and pack_1) or pack_2
+ if trace_packing then
+ report_otf("start packing: stage 2, pass %s",pass)
+ end
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
for unicode, description in next, data.descriptions do
local kerns = description.kerns
if kerns then
- description.kerns = pack(kerns)
+ description.kerns = pack_normal(kerns)
end
local math = description.math
if math then
local kerns = math.kerns
if kerns then
- math.kerns = pack(kerns)
+ math.kerns = pack_normal(kerns)
end
end
local anchors = description.anchors
if anchors then
- description.anchors = pack(anchors)
+ description.anchors = pack_normal(anchors)
end
local mlookups = description.mlookups
if mlookups then
for tag, mlookup in next, mlookups do
- mlookups[tag] = pack(mlookup)
+ mlookups[tag] = pack_normal(mlookup)
end
end
end
@@ -314,9 +469,9 @@ local function packdata(data)
if rules then
for i=1,#rules do -- was next loop
local rule = rules[i]
- local r = rule.before if r then rule.before = pack(r) end
- local r = rule.after if r then rule.after = pack(r) end
- local r = rule.current if r then rule.current = pack(r) end
+ local r = rule.before if r then rule.before = pack_normal(r) end
+ local r = rule.after if r then rule.after = pack_normal(r) end
+ local r = rule.current if r then rule.current = pack_normal(r) end
end
end
end
@@ -324,7 +479,7 @@ local function packdata(data)
local sequences = resources.sequences
if sequences then
for feature, sequence in next, sequences do
- sequence.features = pack(sequence.features)
+ sequence.features = pack_normal(sequence.features)
end
end
if not success(2,pass) then
@@ -333,15 +488,15 @@ local function packdata(data)
end
for pass=1,2 do
- local pack = (pass == 1 and pack_1) or pack_2
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
for unicode, description in next, data.descriptions do
local slookups = description.slookups
if slookups then
- description.slookups = pack(slookups)
+ description.slookups = pack_normal(slookups)
end
local mlookups = description.mlookups
if mlookups then
- description.mlookups = pack(mlookups)
+ description.mlookups = pack_normal(mlookups)
end
end
end