diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-otp.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-otp.lua | 323 |
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 |