diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
commit | 8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch) | |
tree | 94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/font-oup.lua | |
parent | f5aed2e51223c36c84c5f25a6cad238b2af59087 (diff) | |
download | context-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz |
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/font-oup.lua')
-rw-r--r-- | tex/context/base/font-oup.lua | 2009 |
1 files changed, 0 insertions, 2009 deletions
diff --git a/tex/context/base/font-oup.lua b/tex/context/base/font-oup.lua deleted file mode 100644 index 004e487c5..000000000 --- a/tex/context/base/font-oup.lua +++ /dev/null @@ -1,2009 +0,0 @@ -if not modules then modules = { } end modules ['font-oup'] = { - version = 1.001, - comment = "companion to font-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local next, type = next, type -local P, R, S = lpeg.P, lpeg.R, lpeg.S -local lpegmatch = lpeg.match -local insert, remove, copy = table.insert, table.remove, table.copy - -local formatters = string.formatters -local sortedkeys = table.sortedkeys -local sortedhash = table.sortedhash -local tohash = table.tohash - -local report = logs.reporter("otf reader") - -local trace_markwidth = false trackers.register("otf.markwidth",function(v) trace_markwidth = v end) - -local readers = fonts.handlers.otf.readers -local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF - -local f_private = formatters["P%05X"] -local f_unicode = formatters["U%05X"] -local f_index = formatters["I%05X"] -local f_character = formatters["%C"] - -local doduplicates = true -- can become an option (pseudo feature) - -local function replaced(list,index,replacement) - if type(list) == "number" then - return replacement - elseif type(replacement) == "table" then - local t = { } - local n = index-1 - for i=1,n do - t[i] = list[i] - end - for i=1,#replacement do - n = n + 1 - t[n] = replacement[i] - end - for i=index+1,#list do - n = n + 1 - t[n] = list[i] - end - else - list[index] = replacement - return list - end -end - -local function unifyresources(fontdata,indices) - local descriptions = fontdata.descriptions - local resources = fontdata.resources - if not descriptions or not resources then - return - end - -- - local variants = fontdata.resources.variants - if variants then - for selector, unicodes in next, variants do - for unicode, index in next, unicodes do - unicodes[unicode] = indices[index] - end - end - end - -- - local function remark(marks) - if marks then - local newmarks = { } - for k, v in next, marks do - local u = indices[k] - if u then - newmarks[u] = v - else - report("discarding mark %i",k) - end - end - return newmarks - end - end - -- - local marks = resources.marks - if marks then - resources.marks = remark(marks) - end - -- - local markclasses = resources.markclasses - if markclasses then - for class, marks in next, markclasses do - markclasses[class] = remark(marks) - end - end - -- - local marksets = resources.marksets - if marksets then - for class, marks in next, marksets do - marksets[class] = remark(marks) - end - end - -- - local done = { } -- we need to deal with shared ! - -- - local duplicates = doduplicates and resources.duplicates - if duplicates and not next(duplicates) then - duplicates = false - end - -- - local function recover(cover) -- can be packed - for i=1,#cover do - local c = cover[i] - if not done[c] then - local t = { } - for k, v in next, c do - t[indices[k]] = v - end - cover[i] = t - done[c] = d - end - end - end - -- - local function recursed(c) -- ligs are not packed - local t = { } - for g, d in next, c do - if type(d) == "table" then - t[indices[g]] = recursed(d) - else - t[g] = indices[d] -- ligature - end - end - return t - end - -- - -- the duplicates need checking (probably only in cjk fonts): currently we only check - -- gsub_single, gsub_alternate and gsub_multiple - -- - local function unifythem(sequences) - if not sequences then - return - end - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - local features = sequence.features - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gsub_single" then - local c = step.coverage - if c then - local t1 = done[c] - if not t1 then - t1 = { } - if duplicates then - for g1, d1 in next, c do - local ug1 = indices[g1] - local ud1 = indices[d1] - t1[ug1] = ud1 - -- - local dg1 = duplicates[ug1] - if dg1 then - for u in next, dg1 do - t1[u] = ud1 - end - end - end - else - for g1, d1 in next, c do - t1[indices[g1]] = indices[d1] - end - end - done[c] = t1 - end - step.coverage = t1 - end - elseif kind == "gpos_pair" then - local c = step.coverage - if c then - local t1 = done[c] - if not t1 then - t1 = { } - for g1, d1 in next, c do - local t2 = done[d1] - if not t2 then - t2 = { } - for g2, d2 in next, d1 do - t2[indices[g2]] = d2 - end - done[d1] = t2 - end - t1[indices[g1]] = t2 - end - done[c] = t1 - end - step.coverage = t1 - end - elseif kind == "gsub_ligature" then - local c = step.coverage - if c then - step.coverage = recursed(c) - end - elseif kind == "gsub_alternate" or kind == "gsub_multiple" then - local c = step.coverage - if c then - local t1 = done[c] - if not t1 then - t1 = { } - if duplicates then - for g1, d1 in next, c do - for i=1,#d1 do - d1[i] = indices[d1[i]] - end - local ug1 = indices[g1] - t1[ug1] = d1 - -- - local dg1 = duplicates[ug1] - if dg1 then - for u in next, dg1 do - t1[u] = copy(d1) - end - end - end - else - for g1, d1 in next, c do - for i=1,#d1 do - d1[i] = indices[d1[i]] - end - t1[indices[g1]] = d1 - end - end - done[c] = t1 - end - step.coverage = t1 - end - elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" or kind == "gpos_mark2ligature" then - local c = step.coverage - if c then - local t1 = done[c] - if not t1 then - t1 = { } - for g1, d1 in next, c do - t1[indices[g1]] = d1 - end - done[c] = t1 - end - step.coverage = t1 - end - local c = step.baseclasses - if c then - local t1 = done[c] - if not t1 then - for g1, d1 in next, c do - local t2 = done[d1] - if not t2 then - t2 = { } - for g2, d2 in next, d1 do - t2[indices[g2]] = d2 - end - done[d1] = t2 - end - c[g1] = t2 - end - done[c] = c - end - end - elseif kind == "gpos_single" or kind == "gpos_cursive" then - local c = step.coverage - if c then - local t1 = done[c] - if not t1 then - t1 = { } - for g1, d1 in next, c do - t1[indices[g1]] = d1 - end - done[c] = t1 - end - step.coverage = t1 - end - end - -- - local rules = step.rules - if rules then - for i=1,#rules do - local rule = rules[i] - -- - local before = rule.before if before then recover(before) end - local after = rule.after if after then recover(after) end - local current = rule.current if current then recover(current) end - -- - local replacements = rule.replacements - if replacements then - if not done[replacements] then - local r = { } - for k, v in next, replacements do - r[indices[k]] = indices[v] - end - rule.replacements = r - done[replacements] = r - end - end - end - end - end - end - end - end - -- - unifythem(resources.sequences) - unifythem(resources.sublookups) -end - -local function copyduplicates(fontdata) - if doduplicates then - local descriptions = fontdata.descriptions - local resources = fontdata.resources - local duplicates = resources.duplicates - if duplicates then - for u, d in next, duplicates do - local du = descriptions[u] - if du then - local t = { f_character(u) } - for u in next, d do - descriptions[u] = copy(du) - t[#t+1] = f_character(u) - end - report("duplicates: % t",t) - else - -- what a mess - end - end - end - end -end - -local ignore = { -- should we fix them? - ["notdef"] = true, - [".notdef"] = true, - ["null"] = true, - [".null"] = true, - ["nonmarkingreturn"] = true, -} - - -local function checklookups(fontdata,missing,nofmissing) - local descriptions = fontdata.descriptions - local resources = fontdata.resources - if missing and nofmissing and nofmissing <= 0 then - return - end - -- - local singles = { } - local alternates = { } - local ligatures = { } - - if not missing then - missing = { } - nofmissing = 0 - for u, d in next, descriptions do - if not d.unicode then - nofmissing = nofmissing + 1 - missing[u] = true - end - end - end - - local function collectthem(sequences) - if not sequences then - return - end - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gsub_single" then - local c = step.coverage - if c then - singles[#singles+1] = c - end - elseif kind == "gsub_alternate" then - local c = step.coverage - if c then - alternates[#alternates+1] = c - end - elseif kind == "gsub_ligature" then - local c = step.coverage - if c then - ligatures[#ligatures+1] = c - end - end - end - end - end - end - - collectthem(resources.sequences) - collectthem(resources.sublookups) - - local loops = 0 - while true do - loops = loops + 1 - local old = nofmissing - for i=1,#singles do - local c = singles[i] - for g1, g2 in next, c do - if missing[g1] then - local u2 = descriptions[g2].unicode - if u2 then - missing[g1] = false - descriptions[g1].unicode = u2 - nofmissing = nofmissing - 1 - end - end - if missing[g2] then - local u1 = descriptions[g1].unicode - if u1 then - missing[g2] = false - descriptions[g2].unicode = u1 - nofmissing = nofmissing - 1 - end - end - end - end - for i=1,#alternates do - local c = alternates[i] - -- maybe first a g1 loop and then a g2 - for g1, d1 in next, c do - if missing[g1] then - for i=1,#d1 do - local g2 = d1[i] - local u2 = descriptions[g2].unicode - if u2 then - missing[g1] = false - descriptions[g1].unicode = u2 - nofmissing = nofmissing - 1 - end - end - end - if not missing[g1] then - for i=1,#d1 do - local g2 = d1[i] - if missing[g2] then - local u1 = descriptions[g1].unicode - if u1 then - missing[g2] = false - descriptions[g2].unicode = u1 - nofmissing = nofmissing - 1 - end - end - end - end - end - end - if nofmissing <= 0 then - report("all done in %s loops",loops) - return - elseif old == nofmissing then - break - end - end - - local t, n -- no need to insert/remove and allocate many times - - local function recursed(c) - for g, d in next, c do - if g ~= "ligature" then - local u = descriptions[g].unicode - if u then - n = n + 1 - t[n] = u - recursed(d) - n = n - 1 - end - elseif missing[d] then - local l = { } - local m = 0 - for i=1,n do - local u = t[i] - if type(u) == "table" then - for i=1,#u do - m = m + 1 - l[m] = u[i] - end - else - m = m + 1 - l[m] = u - end - end - missing[d] = false - descriptions[d].unicode = l - nofmissing = nofmissing - 1 - end - end - end - - if nofmissing > 0 then - t = { } - n = 0 - local loops = 0 - while true do - loops = loops + 1 - local old = nofmissing - for i=1,#ligatures do - recursed(ligatures[i]) - end - if nofmissing <= 0 then - report("all done in %s loops",loops) - return - elseif old == nofmissing then - break - end - end - t = nil - n = 0 - end - - if nofmissing > 0 then - local done = { } - for i, r in next, missing do - if r then - local name = descriptions[i].name or f_index(i) - if not ignore[name] then - done[#done+1] = name - end - end - end - if #done > 0 then - table.sort(done) - report("not unicoded: % t",done) - end - end -end - -local function unifymissing(fontdata) - if not fonts.mappings then - require("font-map") - require("font-agl") - end - local unicodes = { } - local private = fontdata.private - local resources = fontdata.resources - resources.unicodes = unicodes - for unicode, d in next, fontdata.descriptions do - if unicode < privateoffset then - local name = d.name - if name then - unicodes[name] = unicode - end - end - end - fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups) - resources.unicodes = nil -end - -local function unifyglyphs(fontdata,usenames) - local private = fontdata.private or privateoffset - local glyphs = fontdata.glyphs - local indices = { } - local descriptions = { } - local names = usenames and { } - local resources = fontdata.resources - local zero = glyphs[0] - local zerocode = zero.unicode - if not zerocode then - zerocode = private - zero.unicode = zerocode - private = private + 1 - end - descriptions[zerocode] = zero - if names then - local name = glyphs[0].name or f_private(zerocode) - indices[0] = name - names[name] = zerocode - else - indices[0] = zerocode - end - -- - for index=1,#glyphs do - local glyph = glyphs[index] - local unicode = glyph.unicode -- this is the primary one - if not unicode then - -- report("assigning private unicode %U to glyph indexed %05X (%s)",private,index,"unset") - unicode = private - -- glyph.unicode = -1 - if names then - local name = glyph.name or f_private(unicode) - indices[index] = name - names[name] = unicode - else - indices[index] = unicode - end - private = private + 1 - elseif descriptions[unicode] then - -- real weird -report("assigning private unicode %U to glyph indexed %05X (%C)",private,index,unicode) - unicode = private - -- glyph.unicode = -1 - if names then - local name = glyph.name or f_private(unicode) - indices[index] = name - names[name] = unicode - else - indices[index] = unicode - end - private = private + 1 - else - if names then - local name = glyph.name or f_unicode(unicode) - indices[index] = name - names[name] = unicode - else - indices[index] = unicode - end - end - descriptions[unicode] = glyph - end - -- - for index=1,#glyphs do - local math = glyphs[index].math - if math then - local list = math.vparts - if list then - for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - end - local list = math.hparts - if list then - for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - end - local list = math.vvariants - if list then - -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - for i=1,#list do list[i] = indices[list[i]] end - end - local list = math.hvariants - if list then - -- for i=1,#list do local l = list[i] l.glyph = indices[l.glyph] end - for i=1,#list do list[i] = indices[list[i]] end - end - end - end - -- - fontdata.private = private - fontdata.glyphs = nil - fontdata.names = names - fontdata.descriptions = descriptions - fontdata.hashmethod = hashmethod - -- - return indices, names -end - -local p_bogusname = ( - (P("uni") + P("UNI") + P("Uni") + P("U") + P("u")) * S("Xx")^0 * R("09","AF")^1 - + (P("identity") + P("Identity") + P("IDENTITY")) * R("09","AF")^1 - + (P("index") + P("Index") + P("INDEX")) * R("09")^1 -) * P(-1) - -local function stripredundant(fontdata) - local descriptions = fontdata.descriptions - if descriptions then - local n = 0 - local c = 0 - for unicode, d in next, descriptions do - local name = d.name - if name and lpegmatch(p_bogusname,name) then - d.name = nil - n = n + 1 - end - if d.class == "base" then - d.class = nil - c = c + 1 - end - end - if n > 0 then - report("%s bogus names removed (verbose unicode)",n) - end - if c > 0 then - report("%s base class tags removed (default is base)",c) - end - end -end - -function readers.rehash(fontdata,hashmethod) -- TODO: combine loops in one - if not (fontdata and fontdata.glyphs) then - return - end - if hashmethod == "indices" then - fontdata.hashmethod = "indices" - elseif hashmethod == "names" then - fontdata.hashmethod = "names" - local indices = unifyglyphs(fontdata,true) - unifyresources(fontdata,indices) - copyduplicates(fontdata) - unifymissing(fontdata) - -- stripredundant(fontdata) - else - fontdata.hashmethod = "unicode" - local indices = unifyglyphs(fontdata) - unifyresources(fontdata,indices) - copyduplicates(fontdata) - unifymissing(fontdata) - stripredundant(fontdata) - end -end - -function readers.checkhash(fontdata) - local hashmethod = fontdata.hashmethod - if hashmethod == "unicodes" then - fontdata.names = nil -- just to be sure - elseif hashmethod == "names" and fontdata.names then - unifyresources(fontdata,fontdata.names) - copyduplicates(fontdata) - fontdata.hashmethod = "unicode" - fontdata.names = nil -- no need for it - else - readers.rehash(fontdata,"unicode") - end -end - -function readers.addunicodetable(fontdata) - local resources = fontdata.resources - local unicodes = resources.unicodes - if not unicodes then - local descriptions = fontdata.descriptions - if descriptions then - unicodes = { } - resources.unicodes = unicodes - for u, d in next, descriptions do - local n = d.name - if n then - unicodes[n] = u - end - end - end - end -end - --- for the moment here: - -local concat, sort = table.concat, table.sort -local next, type, tostring = next, type, tostring - -local criterium = 1 -local threshold = 0 - -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") - -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 - --- beware: we cannot unpack and repack the same table because then sharing --- interferes (we could catch this if needed) .. so for now: save, reload --- and repack in such cases (never needed anyway) .. a tricky aspect is that --- we then need to sort more thanks to random hashing - -function readers.pack(data) - - if data then - - 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 sequences = resources.sequences - local sublookups = resources.sublookups - local features = resources.features - - local chardata = characters and characters.data - local descriptions = data.descriptions or data.glyphs - - if not descriptions then - return - end - - -- - - 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, descriptions do - local boundingbox = description.boundingbox - if boundingbox then - description.boundingbox = pack_indexed(boundingbox) - 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 - end - - local function packthem(sequences) - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - local order = sequence.order - local features = sequence.features - local flags = sequence.flags - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gpos_pair" then - local c = step.coverage - if c then - if step.format == "kern" then - for g1, d1 in next, c do - c[g1] = pack_normal(d1) - end - else - for g1, d1 in next, c do - for g2, d2 in next, d1 do - local f = d2[1] if f then d2[1] = pack_indexed(f) end - local s = d2[2] if s then d2[2] = pack_indexed(s) end - end - end - end - end - elseif kind == "gpos_single" then - local c = step.coverage - if c then - if step.format == "kern" then - step.coverage = pack_normal(c) - else - for g1, d1 in next, c do - c[g1] = pack_indexed(d1) - end - end - end - elseif kind == "gpos_cursive" then - local c = step.coverage - if c then - for g1, d1 in next, c do - local f = d1[2] if f then d1[2] = pack_indexed(f) end - local s = d1[3] if s then d1[3] = pack_indexed(s) end - end - end - elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" then - local c = step.baseclasses - if c then - for g1, d1 in next, c do - for g2, d2 in next, d1 do - d1[g2] = pack_indexed(d2) - end - end - end - local c = step.coverage - if c then - for g1, d1 in next, c do - d1[2] = pack_indexed(d1[2]) - end - end - elseif kind == "gpos_mark2ligature" then - local c = step.baseclasses - if c then - for g1, d1 in next, c do - for g2, d2 in next, d1 do - for g3, d3 in next, d2 do - d2[g3] = pack_indexed(d3) - end - end - end - end - local c = step.coverage - if c then - for g1, d1 in next, c do - d1[2] = pack_indexed(d1[2]) - end - end - end - -- if ... chain ... - local rules = step.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 - end - end - end - end - if order then - sequence.order = pack_indexed(order) - end - if features then - for script, feature in next, features do - features[script] = pack_normal(feature) - end - end - if flags then - sequence.flags = pack_normal(flags) - end - end - end - - if sequences then - packthem(sequences) - end - - if sublookups then - packthem(sublookups) - end - - if features then - for k, list in next, features do - for feature, spec in next, list do - list[feature] = pack_normal(spec) - 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, descriptions do - local math = description.math - if math then - local kerns = math.kerns - if kerns then - math.kerns = pack_normal(kerns) - end - end - end - - local function packthem(sequences) - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - local features = sequence.features - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gpos_pair" then - local c = step.coverage - if c then - if step.format == "kern" then - -- todo ! - else - for g1, d1 in next, c do - for g2, d2 in next, d1 do - d1[g2] = pack_normal(d2) - end - end - end - end --- elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" or kind == "gpos_mark2ligature" then --- local c = step.baseclasses --- for k, v in next, c do --- c[k] = pack_normal(v) --- end - end - local rules = step.rules - if rules then - for i=1,#rules do - 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 - if features then - sequence.features = pack_normal(features) - end - end - end - if sequences then - packthem(sequences) - end - if sublookups then - packthem(sublookups) - end - -- features - if not success(2,pass) then - -- return - end - end - - for pass=1,2 do - if trace_packing then - report_otf("start packing: stage 3, pass %s",pass) - end - - local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass) - - local function packthem(sequences) - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - local features = sequence.features - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gpos_pair" then - local c = step.coverage - if c then - if step.format == "kern" then - -- todo ! - else - for g1, d1 in next, c do - c[g1] = pack_normal(d1) - end - end - end - end - end - end - end - end - - if sequences then - packthem(sequences) - end - if sublookups then - packthem(sublookups) - end - - end - - end - - end -end - -local unpacked_mt = { - __index = - function(t,k) - t[k] = false - return k -- next time true - end -} - -function readers.unpack(data) - - if data then - local tables = data.tables - if tables then - local resources = data.resources - local descriptions = data.descriptions or data.glyphs - local sequences = resources.sequences - local sublookups = resources.sublookups - local features = resources.features - local unpacked = { } - setmetatable(unpacked,unpacked_mt) - for unicode, description in next, descriptions do - local tv = tables[description.boundingbox] - if tv then - description.boundingbox = tv - 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 - end - - local function unpackthem(sequences) - for i=1,#sequences do - local sequence = sequences[i] - local kind = sequence.type - local steps = sequence.steps - local order = sequence.order - local features = sequence.features - local flags = sequence.flags - local markclass = sequence.markclass - if steps then - for i=1,#steps do - local step = steps[i] - if kind == "gpos_pair" then - local c = step.coverage - if c then - if step.format == "kern" then - for g1, d1 in next, c do - local tv = tables[d1] - if tv then - c[g1] = tv - end - end - else - for g1, d1 in next, c do - local tv = tables[d1] - if tv then - c[g1] = tv - d1 = tv - end - for g2, d2 in next, d1 do - local tv = tables[d2] - if tv then - d1[g2] = tv - d2 = tv - end - local f = tables[d2[1]] if f then d2[1] = f end - local s = tables[d2[2]] if s then d2[2] = s end - end - end - end - end - elseif kind == "gpos_single" then - local c = step.coverage - if c then - if step.format == "kern" then - local tv = tables[c] - if tv then - step.coverage = tv - end - else - for g1, d1 in next, c do - local tv = tables[d1] - if tv then - c[g1] = tv - end - end - end - end - elseif kind == "gpos_cursive" then - local c = step.coverage - if c then - for g1, d1 in next, c do - local f = tables[d1[2]] if f then d1[2] = f end - local s = tables[d1[3]] if s then d1[3] = s end - end - end - elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" then - local c = step.baseclasses - if c then --- for k, v in next, c do --- local tv = tables[v] --- if tv then --- c[k] = tv --- end --- end - for g1, d1 in next, c do - for g2, d2 in next, d1 do - local tv = tables[d2] - if tv then - d1[g2] = tv - end - end - end - end - local c = step.coverage - if c then - for g1, d1 in next, c do - local tv = tables[d1[2]] - if tv then - d1[2] = tv - end - end - end - elseif kind == "gpos_mark2ligature" then - local c = step.baseclasses - if c then --- for k, v in next, c do --- local tv = tables[v] --- if tv then --- c[k] = tv --- end --- end - for g1, d1 in next, c do - for g2, d2 in next, d1 do - for g3, d3 in next, d2 do - local tv = tables[d2[g3]] - if tv then - d2[g3] = tv - end - end - end - end - end - local c = step.coverage - if c then - for g1, d1 in next, c do - local tv = tables[d1[2]] - if tv then - d1[2] = tv - end - end - end - end - local rules = step.rules - if rules then - for i=1,#rules do - local rule = rules[i] - local before = rule.before - if before then - local tv = tables[before] - if tv then - rule.before = tv - before = tv - end - for i=1,#before do - local tv = tables[before[i]] - if tv then - before[i] = tv - end - end - end - local after = rule.after - if after then - local tv = tables[after] - if tv then - rule.after = tv - after = tv - end - for i=1,#after do - local tv = tables[after[i]] - if tv then - after[i] = tv - end - end - end - local current = rule.current - if current then - local tv = tables[current] - if tv then - rule.current = tv - current = tv - end - for i=1,#current do - local tv = tables[current[i]] - if tv then - current[i] = tv - end - end - end - local replacements = rule.replacements - if replacements then - local tv = tables[replace] - if tv then - rule.replacements = tv - end - end - end - end - end - end - if features then - local tv = tables[features] - if tv then - sequence.features = tv - features = tv - end - for script, feature in next, features do - local tv = tables[feature] - if tv then - features[script] = tv - end - end - end - if order then - local tv = tables[order] - if tv then - sequence.order = tv - end - end - if flags then - local tv = tables[flags] - if tv then - sequence.flags = tv - end - end - end - end - - if sequences then - unpackthem(sequences) - end - - if sublookups then - unpackthem(sublookups) - end - - if features then - for k, list in next, features do - for feature, spec in next, list do - local tv = tables[spec] - if tv then - list[feature] = tv - end - end - end - end - - data.tables = nil - end - end -end - -local mt = { - __index = function(t,k) -- maybe set it - if k == "height" then - local ht = t.boundingbox[4] - return ht < 0 and 0 or ht - elseif k == "depth" then - local dp = -t.boundingbox[2] - return dp < 0 and 0 or dp - elseif k == "width" then - return 0 - elseif k == "name" then -- or maybe uni* - return forcenotdef and ".notdef" - end - end -} - -local function sameformat(sequence,steps,first,nofsteps,kind) - return true -end - -local function mergesteps_1(lookup,strict) - local steps = lookup.steps - local nofsteps = lookup.nofsteps - local first = steps[1] - if strict then - local f = first.format - for i=2,nofsteps do - if steps[i].format ~= f then - report("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) - return 0 - end - end - end - report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - local target = first.coverage - for i=2,nofsteps do - for k, v in next, steps[i].coverage do - if not target[k] then - target[k] = v - end - end - end - lookup.nofsteps = 1 - lookup.merged = true - lookup.steps = { first } - return nofsteps - 1 -end - - -local function mergesteps_2(lookup,strict) -- pairs - local steps = lookup.steps - local nofsteps = lookup.nofsteps - local first = steps[1] - if strict then - local f = first.format - for i=2,nofsteps do - if steps[i].format ~= f then - report("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) - return 0 - end - end - end - report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - local target = first.coverage - for i=2,nofsteps do - for k, v in next, steps[i].coverage do - local tk = target[k] - if tk then - for k, v in next, v do - if not tk[k] then - tk[k] = v - end - end - else - target[k] = v - end - end - end - lookup.nofsteps = 1 - lookup.steps = { first } - return nofsteps - 1 -end - - -local function mergesteps_3(lookup,strict) -- marks - local steps = lookup.steps - local nofsteps = lookup.nofsteps - local first = steps[1] - report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - local baseclasses = { } - local coverage = { } - local used = { } - for i=1,nofsteps do - local offset = i*10 - local step = steps[i] - for k, v in sortedhash(step.baseclasses) do - baseclasses[offset+k] = v - end - for k, v in next, step.coverage do - local tk = coverage[k] - if tk then - for k, v in next, v do - if not tk[k] then - tk[k] = v - local c = offset + v[1] - v[1] = c - if not used[c] then - used[c] = true - end - end - end - else - coverage[k] = v - local c = offset + v[1] - v[1] = c - if not used[c] then - used[c] = true - end - end - end - end - for k, v in next, baseclasses do - if not used[k] then - baseclasses[k] = nil - report("discarding not used baseclass %i",k) - end - end - first.baseclasses = baseclasses - first.coverage = coverage - lookup.nofsteps = 1 - lookup.steps = { first } - return nofsteps - 1 -end - -local function nested(old,new) - for k, v in next, old do - if k == "ligature" then - if not new.ligature then - new.ligature = v - end - else - local n = new[k] - if n then - nested(v,n) - else - new[k] = v - end - end - end -end - -local function mergesteps_4(lookup) -- ligatures - local steps = lookup.steps - local nofsteps = lookup.nofsteps - local first = steps[1] - report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - local target = first.coverage - for i=2,nofsteps do - for k, v in next, steps[i].coverage do - local tk = target[k] - if tk then - nested(v,tk) - else - target[k] = v - end - end - end - lookup.nofsteps = 1 - lookup.steps = { first } - return nofsteps - 1 -end - -local function checkkerns(lookup) - local steps = lookup.steps - local nofsteps = lookup.nofsteps - for i=1,nofsteps do - local step = steps[i] - if step.format == "pair" then - local coverage = step.coverage - local kerns = true - for g1, d1 in next, coverage do - if d1[1] ~= 0 or d1[2] ~= 0 or d1[4] ~= 0 then - kerns = false - break - end - end - if kerns then - report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) - for g1, d1 in next, coverage do - coverage[g1] = d1[3] - end - step.format = "kern" - end - end - end -end - -local function checkpairs(lookup) - local steps = lookup.steps - local nofsteps = lookup.nofsteps - local kerned = 0 - for i=1,nofsteps do - local step = steps[i] - if step.format == "pair" then - local coverage = step.coverage - local kerns = true - for g1, d1 in next, coverage do - for g2, d2 in next, d1 do - if d2[2] then - kerns = false - break - else - local v = d2[1] - if v[1] ~= 0 or v[2] ~= 0 or v[4] ~= 0 then - kerns = false - break - end - end - end - end - if kerns then - report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) - for g1, d1 in next, coverage do - for g2, d2 in next, d1 do - d1[g2] = d2[1][3] - end - end - step.format = "kern" - kerned = kerned + 1 - end - end - end - return kerned -end - -function readers.compact(data) - if not data or data.compacted then - return - else - data.compacted = true - end - local resources = data.resources - local merged = 0 - local kerned = 0 - local allsteps = 0 - local function compact(what) - local lookups = resources[what] - if lookups then - for i=1,#lookups do - local lookup = lookups[i] - local nofsteps = lookup.nofsteps - allsteps = allsteps + nofsteps - if nofsteps > 1 then - local kind = lookup.type - if kind == "gsub_single" or kind == "gsub_alternate" or kind == "gsub_multiple" then - merged = merged + mergesteps_1(lookup) - elseif kind == "gsub_ligature" then - merged = merged + mergesteps_4(lookup) - elseif kind == "gpos_single" then - merged = merged + mergesteps_1(lookup,true) - checkkerns(lookup) - elseif kind == "gpos_pair" then - merged = merged + mergesteps_2(lookup,true) - kerned = kerned + checkpairs(lookup) - elseif kind == "gpos_cursive" then - merged = merged + mergesteps_2(lookup) - elseif kind == "gpos_mark2mark" or kind == "gpos_mark2base" or kind == "gpos_mark2ligature" then - merged = merged + mergesteps_3(lookup) - end - end - end - else - report("no lookups in %a",what) - end - end - compact("sequences") - compact("sublookups") - if merged > 0 then - report("%i steps of %i removed due to merging",merged,allsteps) - end - if kerned > 0 then - report("%i steps of %i steps turned from pairs into kerns",kerned,allsteps) - end -end - -function readers.expand(data) - if not data or data.expanded then - return - else - data.expanded = true - end - local resources = data.resources - local sublookups = resources.sublookups - local sequences = resources.sequences -- were one level up - local markclasses = resources.markclasses - local descriptions = data.descriptions - if descriptions then - local defaultwidth = resources.defaultwidth or 0 - local defaultheight = resources.defaultheight or 0 - local defaultdepth = resources.defaultdepth or 0 - local basename = trace_markwidth and file.basename(resources.filename) - for u, d in next, descriptions do - local bb = d.boundingbox - local wd = d.width - if not wd then - -- or bb? - d.width = defaultwidth - elseif trace_markwidth and wd ~= 0 and d.class == "mark" then - report("mark %a with width %b found in %a",d.name or "<noname>",wd,basename) - end - if bb then - local ht = bb[4] - local dp = -bb[2] - if ht == 0 or ht < 0 then - -- not set - else - d.height = ht - end - if dp == 0 or dp < 0 then - -- not set - else - d.depth = dp - end - end - end - end - local function expandlookups(sequences) - if sequences then - -- we also need to do sublookups - for i=1,#sequences do - local sequence = sequences[i] - local steps = sequence.steps - if steps then - local kind = sequence.type - local markclass = sequence.markclass - if markclass then - if not markclasses then - report_warning("missing markclasses") - sequence.markclass = false - else - sequence.markclass = markclasses[markclass] - end - end - for i=1,sequence.nofsteps do - local step = steps[i] - local baseclasses = step.baseclasses - if baseclasses then - local coverage = step.coverage - for k, v in next, coverage do - v[1] = baseclasses[v[1]] -- slot 1 is a placeholder - end - elseif kind == "gpos_cursive" then - local coverage = step.coverage - for k, v in next, coverage do - v[1] = coverage -- slot 1 is a placeholder - end - end - local rules = step.rules - if rules then - local rulehash = { } - local rulesize = 0 - local coverage = { } - local lookuptype = sequence.type - step.coverage = coverage -- combined hits - for nofrules=1,#rules do - local rule = rules[nofrules] - local current = rule.current - local before = rule.before - local after = rule.after - local replacements = rule.replacements or false - local sequence = { } - local nofsequences = 0 - if before then - for n=1,#before do - nofsequences = nofsequences + 1 - sequence[nofsequences] = before[n] - end - end - local start = nofsequences + 1 - for n=1,#current do - nofsequences = nofsequences + 1 - sequence[nofsequences] = current[n] - end - local stop = nofsequences - if after then - for n=1,#after do - nofsequences = nofsequences + 1 - sequence[nofsequences] = after[n] - end - end - local lookups = rule.lookups or false - local subtype = nil - if lookups then - for k, v in next, lookups do - local lookup = sublookups[v] - if lookup then - lookups[k] = lookup - if not subtype then - subtype = lookup.type - end - else - -- already expanded - end - end - end - if sequence[1] then -- we merge coverage into one - rulesize = rulesize + 1 - rulehash[rulesize] = { - nofrules, -- 1 - lookuptype, -- 2 - sequence, -- 3 - start, -- 4 - stop, -- 5 - lookups, -- 6 (6/7 also signal of what to do) - replacements, -- 7 - subtype, -- 8 - } - for unic in next, sequence[start] do - local cu = coverage[unic] - if not cu then - coverage[unic] = rulehash -- can now be done cleaner i think - end - end - end - end - end - end - end - end - end - end - expandlookups(sequences) - expandlookups(sublookups) -end |