diff options
Diffstat (limited to 'tex/context/base/font-otp.lua')
-rw-r--r-- | tex/context/base/font-otp.lua | 1754 |
1 files changed, 877 insertions, 877 deletions
diff --git a/tex/context/base/font-otp.lua b/tex/context/base/font-otp.lua index f0c2edd86..217bb7535 100644 --- a/tex/context/base/font-otp.lua +++ b/tex/context/base/font-otp.lua @@ -1,877 +1,877 @@ -if not modules then modules = { } end modules ['font-otp'] = {
- version = 1.001,
- comment = "companion to font-otf.lua (packing)",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- 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 { }
-
-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_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_normal(v)
- elseif v == true then
- s[n] = k .. "+" -- "=true"
- elseif v then
- s[n] = k .. "=" .. v
- else
- s[n] = k .. "-" -- "=false"
- 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
-
-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_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 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_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)
- 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_final(v)
- -- v == number
- if c[v] <= criterium then
- return t[v]
- else
- -- compact hash
- local hv = hh[v]
- if hv then
- return hv
- else
- ntt = ntt + 1
- tt[ntt] = t[v]
- hh[v] = ntt
- cc[ntt] = c[v]
- return ntt
- end
- end
- end
- local function success(stage,pass)
- if nt == 0 then
- if trace_loading or trace_packing then
- report_otf("pack quality: nothing to pack")
- end
- return false
- elseif nt >= threshold then
- local one, two, rest = 0, 0, 0
- if pass == 1 then
- for k,v in next, c do
- if v == 1 then
- one = one + 1
- elseif v == 2 then
- two = two + 1
- else
- rest = rest + 1
- end
- end
- else
- for k,v in next, cc do
- if v > 20 then
- rest = rest + 1
- elseif v > 10 then
- two = two + 1
- else
- one = one + 1
- end
- end
- data.tables = tt
- end
- 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 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
- 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_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_indexed(t) end
- local t = slookup[3] if t then slookup[3] = pack_indexed(t) end
- elseif what ~= "substitution" then
- slookups[tag] = pack_indexed(slookup) -- true is new
- end
- end
- end
- local mlookups = description.mlookups
- if mlookups then
- for tag, mlookup in next, mlookups do
- local what = lookuptypes[tag]
- if what == "pair" then
- for i=1,#mlookup do
- local lookup = mlookup[i]
- 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_indexed(mlookup[i]) -- true is new
- end
- end
- end
- end
- local kerns = description.kerns
- if kerns then
- for tag, kern in next, kerns do
- kerns[tag] = pack_flat(kern)
- end
- end
- local math = description.math
- if math then
- local kerns = math.kerns
- if kerns then
- for tag, kern in next, kerns do
- kerns[tag] = pack_normal(kern)
- end
- end
- end
- local anchors = description.anchors
- if anchors then
- for what, anchor in next, anchors do
- if what == "baselig" then
- for _, a in next, anchor do
- for k=1,#a do
- a[k] = pack_indexed(a[k])
- end
- end
- else
- for k, v in next, anchor do
- anchor[k] = pack_indexed(v)
- end
- end
- end
- end
- local altuni = description.altuni
- if altuni then
- for i=1,#altuni do
- altuni[i] = pack_flat(altuni[i])
- end
- end
- end
- local lookups = data.lookups
- if lookups then
- for _, lookup in next, lookups do
- local rules = lookup.rules
- if rules then
- for i=1,#rules do
- local rule = rules[i]
- 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_indexed(r) end -- can have ""
- -- local r = rule.lookups if r then rule.lookups = pack_flat(r) end -- can have holes (already taken care of some cases)
- end
- end
- end
- end
- 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_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_normal(anchor)
- end
- end
- local sequences = resources.sequences
- if sequences then
- for feature, sequence in next, sequences do
- local flags = sequence.flags
- if flags then
- sequence.flags = pack_normal(flags)
- end
- local subtables = sequence.subtables
- if subtables then
- sequence.subtables = pack_normal(subtables)
- end
- local features = sequence.features
- if features then
- for script, feature in next, features do
- features[script] = pack_normal(feature)
- end
- end
- end
- end
- local lookups = resources.lookups
- if lookups then
- for name, lookup in next, lookups do
- local flags = lookup.flags
- if flags then
- lookup.flags = pack_normal(flags)
- end
- local subtables = lookup.subtables
- if subtables then
- lookup.subtables = pack_normal(subtables)
- end
- end
- end
- local features = resources.features
- if features then
- for _, what in next, glists do
- local list = features[what]
- if list then
- for feature, spec in next, list do
- list[feature] = pack_normal(spec)
- end
- end
- end
- end
- if not success(1,pass) then
- return
- end
- end
- if nt > 0 then
- for pass=1,2 do
- 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_normal(kerns)
- end
- local math = description.math
- if math then
- local kerns = math.kerns
- if kerns then
- math.kerns = pack_normal(kerns)
- end
- end
- local anchors = description.anchors
- if anchors then
- description.anchors = pack_normal(anchors)
- end
- local mlookups = description.mlookups
- if mlookups then
- for tag, mlookup in next, mlookups do
- mlookups[tag] = pack_normal(mlookup)
- end
- end
- local altuni = description.altuni
- if altuni then
- description.altuni = pack_normal(altuni)
- end
- end
- local lookups = data.lookups
- if lookups then
- for _, lookup in next, lookups do
- local rules = lookup.rules
- 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_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
- end
- local sequences = resources.sequences
- if sequences then
- for feature, sequence in next, sequences do
- sequence.features = pack_normal(sequence.features)
- end
- end
- if not success(2,pass) then
- -- return
- end
- end
-
- for pass=1,2 do
- 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_normal(slookups)
- end
- local mlookups = description.mlookups
- if mlookups then
- description.mlookups = pack_normal(mlookups)
- end
- end
- end
-
- end
- end
-end
-
-local unpacked_mt = {
- __index =
- function(t,k)
- t[k] = false
- return k -- next time true
- end
-}
-
-local function unpackdata(data)
- if data then
- local tables = data.tables
- if tables then
- local resources = data.resources
- local lookuptypes = resources.lookuptypes
- local unpacked = { }
- setmetatable(unpacked,unpacked_mt)
- for unicode, description in next, data.descriptions do
- local tv = tables[description.boundingbox]
- if tv then
- description.boundingbox = tv
- end
- local slookups = description.slookups
- if slookups then
- local tv = tables[slookups]
- if tv then
- description.slookups = tv
- slookups = unpacked[tv]
- end
- if slookups then
- for tag, lookup in next, slookups do
- local what = lookuptypes[tag]
- if what == "pair" then
- local tv = tables[lookup[2]]
- if tv then
- lookup[2] = tv
- end
- local tv = tables[lookup[3]]
- if tv then
- lookup[3] = tv
- end
- elseif what ~= "substitution" then
- local tv = tables[lookup]
- if tv then
- slookups[tag] = tv
- end
- end
- end
- end
- end
- local mlookups = description.mlookups
- if mlookups then
- local tv = tables[mlookups]
- if tv then
- description.mlookups = tv
- mlookups = unpacked[tv]
- end
- if mlookups then
- for tag, list in next, mlookups do
- local tv = tables[list]
- if tv then
- mlookups[tag] = tv
- list = unpacked[tv]
- end
- if list then
- local what = lookuptypes[tag]
- if what == "pair" then
- for i=1,#list do
- local lookup = list[i]
- local tv = tables[lookup[2]]
- if tv then
- lookup[2] = tv
- end
- local tv = tables[lookup[3]]
- if tv then
- lookup[3] = tv
- end
- end
- elseif what ~= "substitution" then
- for i=1,#list do
- local tv = tables[list[i]]
- if tv then
- list[i] = tv
- end
- end
- end
- end
- end
- end
- end
- local kerns = description.kerns
- if kerns then
- local tm = tables[kerns]
- if tm then
- description.kerns = tm
- kerns = unpacked[tm]
- end
- if kerns then
- for k, kern in next, kerns do
- local tv = tables[kern]
- if tv then
- kerns[k] = tv
- end
- end
- end
- end
- local math = description.math
- if math then
- local kerns = math.kerns
- if kerns then
- local tm = tables[kerns]
- if tm then
- math.kerns = tm
- kerns = unpacked[tm]
- end
- if kerns then
- for k, kern in next, kerns do
- local tv = tables[kern]
- if tv then
- kerns[k] = tv
- end
- end
- end
- end
- end
- local anchors = description.anchors
- if anchors then
- local ta = tables[anchors]
- if ta then
- description.anchors = ta
- anchors = unpacked[ta]
- end
- if anchors then
- for tag, anchor in next, anchors do
- if tag == "baselig" then
- for _, list in next, anchor do
- for i=1,#list do
- local tv = tables[list[i]]
- if tv then
- list[i] = tv
- end
- end
- end
- else
- for a, data in next, anchor do
- local tv = tables[data]
- if tv then
- anchor[a] = tv
- end
- end
- end
- end
- end
- end
- local altuni = description.altuni
- if altuni then
- local altuni = tables[altuni]
- if altuni then
- description.altuni = altuni
- for i=1,#altuni do
- local tv = tables[altuni[i]]
- if tv then
- altuni[i] = tv
- end
- end
- end
- end
- end
- local lookups = data.lookups
- if lookups then
- for _, lookup in next, lookups do
- local rules = lookup.rules
- if rules then
- for i=1,#rules do -- was next loop
- local rule = rules[i]
- local before = rule.before
- if before then
- local tv = tables[before]
- if tv then
- rule.before = tv
- before = unpacked[tv]
- end
- if before then
- for i=1,#before do
- local tv = tables[before[i]]
- if tv then
- before[i] = tv
- end
- end
- end
- end
- local after = rule.after
- if after then
- local tv = tables[after]
- if tv then
- rule.after = tv
- after = unpacked[tv]
- end
- if after then
- for i=1,#after do
- local tv = tables[after[i]]
- if tv then
- after[i] = tv
- end
- end
- end
- end
- local current = rule.current
- if current then
- local tv = tables[current]
- if tv then
- rule.current = tv
- current = unpacked[tv]
- end
- if current then
- for i=1,#current do
- local tv = tables[current[i]]
- if tv then
- current[i] = tv
- end
- end
- end
- end
- local replacements = rule.replacements
- if replacements then
- local tv = tables[replacements]
- if tv then
- rule.replacements = tv
- end
- end
- local fore = rule.fore
- if fore then
- local tv = tables[fore]
- if tv then
- rule.fore = tv
- end
- end
- local back = rule.back
- if back then
- local tv = tables[back]
- if tv then
- rule.back = tv
- end
- end
- local names = rule.names
- if names then
- local tv = tables[names]
- if tv then
- rule.names = tv
- end
- end
- local lookups = rule.lookups
- if lookups then
- local tv = tables[lookups]
- if tv then
- rule.lookups = tv
- end
- end
- end
- end
- end
- end
- local anchor_to_lookup = resources.anchor_to_lookup
- if anchor_to_lookup then
- for anchor, lookup in next, anchor_to_lookup do
- local tv = tables[lookup]
- if tv then
- anchor_to_lookup[anchor] = tv
- end
- end
- end
- local lookup_to_anchor = resources.lookup_to_anchor
- if lookup_to_anchor then
- for lookup, anchor in next, lookup_to_anchor do
- local tv = tables[anchor]
- if tv then
- lookup_to_anchor[lookup] = tv
- end
- end
- end
- local ls = resources.sequences
- if ls then
- for _, feature in next, ls do
- local flags = feature.flags
- if flags then
- local tv = tables[flags]
- if tv then
- feature.flags = tv
- end
- end
- local subtables = feature.subtables
- if subtables then
- local tv = tables[subtables]
- if tv then
- feature.subtables = tv
- end
- end
- local features = feature.features
- if features then
- local tv = tables[features]
- if tv then
- feature.features = tv
- features = unpacked[tv]
- end
- if features then
- for script, data in next, features do
- local tv = tables[data]
- if tv then
- features[script] = tv
- end
- end
- end
- end
- end
- end
- local lookups = resources.lookups
- if lookups then
- for _, lookup in next, lookups do
- local flags = lookup.flags
- if flags then
- local tv = tables[flags]
- if tv then
- lookup.flags = tv
- end
- end
- local subtables = lookup.subtables
- if subtables then
- local tv = tables[subtables]
- if tv then
- lookup.subtables = tv
- end
- end
- end
- end
- local features = resources.features
- if features then
- for _, what in next, glists do
- local feature = features[what]
- if feature then
- for tag, spec in next, feature do
- local tv = tables[spec]
- if tv then
- feature[tag] = tv
- end
- end
- end
- end
- end
- data.tables = nil
- end
- end
-end
-
-if otf.enhancers.register then
-
- otf.enhancers.register( "pack", packdata)
- otf.enhancers.register("unpack",unpackdata)
-
--- todo: directive
-
-end
-
-otf.enhancers.unpack = unpackdata -- used elsewhere
+if not modules then modules = { } end modules ['font-otp'] = { + version = 1.001, + comment = "companion to font-otf.lua (packing)", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- 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 { } + +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_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_normal(v) + elseif v == true then + s[n] = k .. "+" -- "=true" + elseif v then + s[n] = k .. "=" .. v + else + s[n] = k .. "-" -- "=false" + 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 + +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_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 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_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) + 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_final(v) + -- v == number + if c[v] <= criterium then + return t[v] + else + -- compact hash + local hv = hh[v] + if hv then + return hv + else + ntt = ntt + 1 + tt[ntt] = t[v] + hh[v] = ntt + cc[ntt] = c[v] + return ntt + end + end + end + local function success(stage,pass) + if nt == 0 then + if trace_loading or trace_packing then + report_otf("pack quality: nothing to pack") + end + return false + elseif nt >= threshold then + local one, two, rest = 0, 0, 0 + if pass == 1 then + for k,v in next, c do + if v == 1 then + one = one + 1 + elseif v == 2 then + two = two + 1 + else + rest = rest + 1 + end + end + else + for k,v in next, cc do + if v > 20 then + rest = rest + 1 + elseif v > 10 then + two = two + 1 + else + one = one + 1 + end + end + data.tables = tt + end + 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 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 + 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_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_indexed(t) end + local t = slookup[3] if t then slookup[3] = pack_indexed(t) end + elseif what ~= "substitution" then + slookups[tag] = pack_indexed(slookup) -- true is new + end + end + end + local mlookups = description.mlookups + if mlookups then + for tag, mlookup in next, mlookups do + local what = lookuptypes[tag] + if what == "pair" then + for i=1,#mlookup do + local lookup = mlookup[i] + 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_indexed(mlookup[i]) -- true is new + end + end + end + end + local kerns = description.kerns + if kerns then + for tag, kern in next, kerns do + kerns[tag] = pack_flat(kern) + end + end + local math = description.math + if math then + local kerns = math.kerns + if kerns then + for tag, kern in next, kerns do + kerns[tag] = pack_normal(kern) + end + end + end + local anchors = description.anchors + if anchors then + for what, anchor in next, anchors do + if what == "baselig" then + for _, a in next, anchor do + for k=1,#a do + a[k] = pack_indexed(a[k]) + end + end + else + for k, v in next, anchor do + anchor[k] = pack_indexed(v) + end + end + end + end + local altuni = description.altuni + if altuni then + for i=1,#altuni do + altuni[i] = pack_flat(altuni[i]) + end + end + end + local lookups = data.lookups + if lookups then + for _, lookup in next, lookups do + local rules = lookup.rules + if rules then + for i=1,#rules do + local rule = rules[i] + 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_indexed(r) end -- can have "" + -- local r = rule.lookups if r then rule.lookups = pack_flat(r) end -- can have holes (already taken care of some cases) + end + end + end + end + 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_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_normal(anchor) + end + end + local sequences = resources.sequences + if sequences then + for feature, sequence in next, sequences do + local flags = sequence.flags + if flags then + sequence.flags = pack_normal(flags) + end + local subtables = sequence.subtables + if subtables then + sequence.subtables = pack_normal(subtables) + end + local features = sequence.features + if features then + for script, feature in next, features do + features[script] = pack_normal(feature) + end + end + end + end + local lookups = resources.lookups + if lookups then + for name, lookup in next, lookups do + local flags = lookup.flags + if flags then + lookup.flags = pack_normal(flags) + end + local subtables = lookup.subtables + if subtables then + lookup.subtables = pack_normal(subtables) + end + end + end + local features = resources.features + if features then + for _, what in next, glists do + local list = features[what] + if list then + for feature, spec in next, list do + list[feature] = pack_normal(spec) + end + end + end + end + if not success(1,pass) then + return + end + end + if nt > 0 then + for pass=1,2 do + 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_normal(kerns) + end + local math = description.math + if math then + local kerns = math.kerns + if kerns then + math.kerns = pack_normal(kerns) + end + end + local anchors = description.anchors + if anchors then + description.anchors = pack_normal(anchors) + end + local mlookups = description.mlookups + if mlookups then + for tag, mlookup in next, mlookups do + mlookups[tag] = pack_normal(mlookup) + end + end + local altuni = description.altuni + if altuni then + description.altuni = pack_normal(altuni) + end + end + local lookups = data.lookups + if lookups then + for _, lookup in next, lookups do + local rules = lookup.rules + 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_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 + end + local sequences = resources.sequences + if sequences then + for feature, sequence in next, sequences do + sequence.features = pack_normal(sequence.features) + end + end + if not success(2,pass) then + -- return + end + end + + for pass=1,2 do + 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_normal(slookups) + end + local mlookups = description.mlookups + if mlookups then + description.mlookups = pack_normal(mlookups) + end + end + end + + end + end +end + +local unpacked_mt = { + __index = + function(t,k) + t[k] = false + return k -- next time true + end +} + +local function unpackdata(data) + if data then + local tables = data.tables + if tables then + local resources = data.resources + local lookuptypes = resources.lookuptypes + local unpacked = { } + setmetatable(unpacked,unpacked_mt) + for unicode, description in next, data.descriptions do + local tv = tables[description.boundingbox] + if tv then + description.boundingbox = tv + end + local slookups = description.slookups + if slookups then + local tv = tables[slookups] + if tv then + description.slookups = tv + slookups = unpacked[tv] + end + if slookups then + for tag, lookup in next, slookups do + local what = lookuptypes[tag] + if what == "pair" then + local tv = tables[lookup[2]] + if tv then + lookup[2] = tv + end + local tv = tables[lookup[3]] + if tv then + lookup[3] = tv + end + elseif what ~= "substitution" then + local tv = tables[lookup] + if tv then + slookups[tag] = tv + end + end + end + end + end + local mlookups = description.mlookups + if mlookups then + local tv = tables[mlookups] + if tv then + description.mlookups = tv + mlookups = unpacked[tv] + end + if mlookups then + for tag, list in next, mlookups do + local tv = tables[list] + if tv then + mlookups[tag] = tv + list = unpacked[tv] + end + if list then + local what = lookuptypes[tag] + if what == "pair" then + for i=1,#list do + local lookup = list[i] + local tv = tables[lookup[2]] + if tv then + lookup[2] = tv + end + local tv = tables[lookup[3]] + if tv then + lookup[3] = tv + end + end + elseif what ~= "substitution" then + for i=1,#list do + local tv = tables[list[i]] + if tv then + list[i] = tv + end + end + end + end + end + end + end + local kerns = description.kerns + if kerns then + local tm = tables[kerns] + if tm then + description.kerns = tm + kerns = unpacked[tm] + end + if kerns then + for k, kern in next, kerns do + local tv = tables[kern] + if tv then + kerns[k] = tv + end + end + end + end + local math = description.math + if math then + local kerns = math.kerns + if kerns then + local tm = tables[kerns] + if tm then + math.kerns = tm + kerns = unpacked[tm] + end + if kerns then + for k, kern in next, kerns do + local tv = tables[kern] + if tv then + kerns[k] = tv + end + end + end + end + end + local anchors = description.anchors + if anchors then + local ta = tables[anchors] + if ta then + description.anchors = ta + anchors = unpacked[ta] + end + if anchors then + for tag, anchor in next, anchors do + if tag == "baselig" then + for _, list in next, anchor do + for i=1,#list do + local tv = tables[list[i]] + if tv then + list[i] = tv + end + end + end + else + for a, data in next, anchor do + local tv = tables[data] + if tv then + anchor[a] = tv + end + end + end + end + end + end + local altuni = description.altuni + if altuni then + local altuni = tables[altuni] + if altuni then + description.altuni = altuni + for i=1,#altuni do + local tv = tables[altuni[i]] + if tv then + altuni[i] = tv + end + end + end + end + end + local lookups = data.lookups + if lookups then + for _, lookup in next, lookups do + local rules = lookup.rules + if rules then + for i=1,#rules do -- was next loop + local rule = rules[i] + local before = rule.before + if before then + local tv = tables[before] + if tv then + rule.before = tv + before = unpacked[tv] + end + if before then + for i=1,#before do + local tv = tables[before[i]] + if tv then + before[i] = tv + end + end + end + end + local after = rule.after + if after then + local tv = tables[after] + if tv then + rule.after = tv + after = unpacked[tv] + end + if after then + for i=1,#after do + local tv = tables[after[i]] + if tv then + after[i] = tv + end + end + end + end + local current = rule.current + if current then + local tv = tables[current] + if tv then + rule.current = tv + current = unpacked[tv] + end + if current then + for i=1,#current do + local tv = tables[current[i]] + if tv then + current[i] = tv + end + end + end + end + local replacements = rule.replacements + if replacements then + local tv = tables[replacements] + if tv then + rule.replacements = tv + end + end + local fore = rule.fore + if fore then + local tv = tables[fore] + if tv then + rule.fore = tv + end + end + local back = rule.back + if back then + local tv = tables[back] + if tv then + rule.back = tv + end + end + local names = rule.names + if names then + local tv = tables[names] + if tv then + rule.names = tv + end + end + local lookups = rule.lookups + if lookups then + local tv = tables[lookups] + if tv then + rule.lookups = tv + end + end + end + end + end + end + local anchor_to_lookup = resources.anchor_to_lookup + if anchor_to_lookup then + for anchor, lookup in next, anchor_to_lookup do + local tv = tables[lookup] + if tv then + anchor_to_lookup[anchor] = tv + end + end + end + local lookup_to_anchor = resources.lookup_to_anchor + if lookup_to_anchor then + for lookup, anchor in next, lookup_to_anchor do + local tv = tables[anchor] + if tv then + lookup_to_anchor[lookup] = tv + end + end + end + local ls = resources.sequences + if ls then + for _, feature in next, ls do + local flags = feature.flags + if flags then + local tv = tables[flags] + if tv then + feature.flags = tv + end + end + local subtables = feature.subtables + if subtables then + local tv = tables[subtables] + if tv then + feature.subtables = tv + end + end + local features = feature.features + if features then + local tv = tables[features] + if tv then + feature.features = tv + features = unpacked[tv] + end + if features then + for script, data in next, features do + local tv = tables[data] + if tv then + features[script] = tv + end + end + end + end + end + end + local lookups = resources.lookups + if lookups then + for _, lookup in next, lookups do + local flags = lookup.flags + if flags then + local tv = tables[flags] + if tv then + lookup.flags = tv + end + end + local subtables = lookup.subtables + if subtables then + local tv = tables[subtables] + if tv then + lookup.subtables = tv + end + end + end + end + local features = resources.features + if features then + for _, what in next, glists do + local feature = features[what] + if feature then + for tag, spec in next, feature do + local tv = tables[spec] + if tv then + feature[tag] = tv + end + end + end + end + end + data.tables = nil + end + end +end + +if otf.enhancers.register then + + otf.enhancers.register( "pack", packdata) + otf.enhancers.register("unpack",unpackdata) + +-- todo: directive + +end + +otf.enhancers.unpack = unpackdata -- used elsewhere |