diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-otf.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-otf.lua | 654 |
1 files changed, 400 insertions, 254 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-otf.lua b/Master/texmf-dist/tex/context/base/font-otf.lua index e8867c53d37..9cecf21f055 100644 --- a/Master/texmf-dist/tex/context/base/font-otf.lua +++ b/Master/texmf-dist/tex/context/base/font-otf.lua @@ -1,6 +1,6 @@ if not modules then modules = { } end modules ['font-otf'] = { version = 1.001, - comment = "companion to font-ini.tex", + 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" @@ -11,6 +11,8 @@ local utf = unicode.utf8 local concat, getn, utfbyte = table.concat, table.getn, utf.byte local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip local type, next, tonumber, tostring = type, next, tonumber, tostring +local abs = math.abs +local lpegmatch = lpeg.match local trace_private = false trackers.register("otf.private", function(v) trace_private = v end) local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) @@ -18,13 +20,10 @@ local trace_features = false trackers.register("otf.features", function(v local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end) local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end) local trace_math = false trackers.register("otf.math", function(v) trace_math = v end) -local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end) +local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) --~ trackers.enable("otf.loading") -local zwnj = 0x200C -local zwj = 0x200D - --[[ldx-- <p>The fontforge table has organized lookups in a certain way. A first implementation of this code was organized featurewise: information related to features was @@ -82,13 +81,16 @@ otf.features.default = otf.features.default or { } otf.enhancers = otf.enhancers or { } otf.glists = { "gsub", "gpos" } -otf.version = 2.628 -- beware: also sync font-mis.lua +otf.version = 2.650 -- beware: also sync font-mis.lua otf.pack = true -- beware: also sync font-mis.lua otf.syncspace = true otf.notdef = false otf.cache = containers.define("fonts", "otf", otf.version, true) otf.cleanup_aat = false -- only context +local wildcard = "*" +local default = "dflt" + --[[ldx-- <p>We start with a lot of tables and related functions.</p> --ldx]]-- @@ -104,6 +106,7 @@ otf.tables.global_fields = table.tohash { "names", "unicodes", "names", +--~ "math", "anchor_classes", "kern_classes", "gpos", @@ -176,7 +179,7 @@ otf.tables.valid_fields = { local function load_featurefile(ff,featurefile) if featurefile then - featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES" + featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea'),'fea') if featurefile and featurefile ~= "" then if trace_loading then logs.report("load otf", "featurefile: %s", featurefile) @@ -190,7 +193,7 @@ function otf.enhance(name,data,filename,verbose) local enhancer = otf.enhancers[name] if enhancer then if (verbose ~= nil and verbose) or trace_loading then - logs.report("load otf","enhance: %s",name) + logs.report("load otf","enhance: %s (%s)",name,filename) end enhancer(data,filename) end @@ -202,8 +205,10 @@ local enhancers = { "patch bugs", "merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage", "cleanup aat", "enrich with features", "add some missing characters", + "reorganize mark classes", "reorganize kerns", -- moved here "flatten glyph lookups", "flatten anchor tables", "flatten feature tables", + "simplify glyph lookups", -- some saving "prepare luatex tables", "analyse features", "rehash features", "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables", @@ -211,6 +216,7 @@ local enhancers = { "share widths", "strip not needed data", "migrate metadata", + "check math parameters", } function otf.load(filename,format,sub,featurefile) @@ -227,7 +233,7 @@ function otf.load(filename,format,sub,featurefile) local data = containers.read(otf.cache(), hash) local size = lfs.attributes(filename,"size") or 0 if not data or data.verbose ~= fonts.verbose or data.size ~= size then - logs.report("load otf","loading: %s",filename) + logs.report("load otf","loading: %s (hash: %s)",filename,hash) local ff, messages if sub then ff, messages = fontloader.open(filename,sub) @@ -235,9 +241,15 @@ function otf.load(filename,format,sub,featurefile) ff, messages = fontloader.open(filename) end if trace_loading and messages and #messages > 0 then - for m=1,#messages do - logs.report("load otf","warning: %s",messages[m]) + if type(messages) == "string" then + logs.report("load otf","warning: %s",messages) + else + for m=1,#messages do + logs.report("load otf","warning: %s",tostring(messages[m])) + end end + else + logs.report("load otf","font loaded okay") end if ff then load_featurefile(ff,featurefile) @@ -248,6 +260,7 @@ function otf.load(filename,format,sub,featurefile) logs.report("load otf","enhancing ...") for e=1,#enhancers do otf.enhance(enhancers[e],data,filename) + io.flush() -- we want instant messages end if otf.pack and not fonts.verbose then otf.enhance("pack",data,filename) @@ -267,6 +280,9 @@ function otf.load(filename,format,sub,featurefile) end end if data then + if trace_defining then + logs.report("define font","loading from cache: %s",hash) + end otf.enhance("unpack",data,filename,false) -- no message here otf.add_dimensions(data) if trace_sequences then @@ -354,6 +370,29 @@ end -- todo: normalize, design_size => designsize +otf.enhancers["reorganize mark classes"] = function(data,filename) + if data.mark_classes then + local unicodes = data.luatex.unicodes + local reverse = { } + for name, class in next, data.mark_classes do + local t = { } + for s in gmatch(class,"[^ ]+") do + local us = unicodes[s] + if type(us) == "table" then + for u=1,#us do + t[us[u]] = true + end + else + t[us] = true + end + end + reverse[name] = t + end + data.luatex.markclasses = reverse + data.mark_classes = nil + end +end + otf.enhancers["prepare luatex tables"] = function(data,filename) data.luatex = data.luatex or { } local luatex = data.luatex @@ -465,140 +504,7 @@ otf.enhancers["analyse marks"] = function(data,filename) end end -local separator = lpeg.S("_.") -local other = lpeg.C((1 - separator)^1) -local ligsplitter = lpeg.Ct(other * (separator * other)^0) - ---~ print(table.serialize(ligsplitter:match("this"))) ---~ print(table.serialize(ligsplitter:match("this.that"))) ---~ print(table.serialize(ligsplitter:match("japan1.123"))) ---~ print(table.serialize(ligsplitter:match("such_so_more"))) ---~ print(table.serialize(ligsplitter:match("such_so_more.that"))) - -otf.enhancers["analyse unicodes"] = function(data,filename) - local tounicode16, tounicode16sequence = fonts.map.tounicode16, fonts.map.tounicode16sequence - local unicodes = data.luatex.unicodes - -- we need to move this code - unicodes['space'] = unicodes['space'] or 32 -- handly later on - unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on - unicodes['zwj'] = unicodes['zwj'] or zwj -- handly later on - unicodes['zwnj'] = unicodes['zwnj'] or zwnj -- handly later on - -- the tounicode mapping is sparse and only needed for alternatives - local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?")) - data.luatex.tounicode, data.luatex.originals = tounicode, originals - local lumunic, uparser, oparser - if false then -- will become an option - lumunic = fonts.map.load_lum_table(filename) - lumunic = lumunic and lumunic.tounicode - end - local cidinfo, cidnames, cidcodes = data.cidinfo - local usedmap = cidinfo and cidinfo.usedname - usedmap = usedmap and fonts.cid.map[usedmap] - if usedmap then - oparser = usedmap and fonts.map.make_name_parser(cidinfo.ordering) - cidnames = usedmap.names - cidcodes = usedmap.unicodes - end - uparser = fonts.map.make_name_parser() - for index, glyph in next, data.glyphs do - local name, unic = glyph.name, glyph.unicode or -1 -- play safe - if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then - local unicode = lumunic and lumunic[name] - if unicode then - originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 - end - -- cidmap heuristics, beware, there is no guarantee for a match unless - -- the chain resolves - if not unicode and usedmap then - local foundindex = oparser:match(name) - if foundindex then - unicode = cidcodes[foundindex] -- name to number - if not unicode then - local reference = cidnames[foundindex] -- number to name - if reference then - local foundindex = oparser:match(reference) - if foundindex then - unicode = cidcodes[foundindex] - if unicode then - originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 - end - end - if not unicode then - local foundcodes, multiple = uparser:match(reference) - if foundcodes then - if multiple then - originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true - else - originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes - end - end - end - end - end - end - end - -- a.whatever or a_b_c.whatever or a_b_c (no numbers) - if not unicode then - local split = ligsplitter:match(name) - local nplit = (split and #split) or 0 - if nplit == 0 then - -- skip - elseif nplit == 1 then - unicode = unicodes[split[1]] - if unicode then - if type(unicode) == "table" then - unicode = unicode[1] - end - originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 - end - else - local done = true - for l=1,nplit do - local u = unicodes[split[l]] - if not u then - done = false - break - elseif type(u) == "table" then - split[l] = u[1] - else - split[l] = u - end - end - if done then - originals[index], tounicode[index], nl, unicode = split, tounicode16sequence(split), nl + 1, true - end - end - end - -- last resort - if not unicode then - local foundcodes, multiple = uparser:match(name) - if foundcodes then - if multiple then - originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true - else - originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes - end - end - end - if not unicode then - originals[index], tounicode[index] = 0xFFFD, "FFFD" - end - end - end - if trace_unimapping then - for index, glyph in table.sortedpairs(data.glyphs) do - local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe - if toun then - logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun) - else - logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic) - end - end - end - if trace_loading and (ns > 0 or nl > 0) then - logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns) - end -end +otf.enhancers["analyse unicodes"] = fonts.map.add_to_unicode otf.enhancers["analyse subtables"] = function(data,filename) data.luatex = data.luatex or { } @@ -658,8 +564,11 @@ otf.enhancers["analyse subtables"] = function(data,filename) (flags.ignorecombiningmarks and "mark") or false, (flags.ignoreligatures and "ligature") or false, (flags.ignorebaseglyphs and "base") or false, - flags.r2l or false + flags.r2l or false, } + if flags.mark_class then + gk.markclass = luatex.markclasses[flags.mark_class] + end end end end @@ -668,7 +577,10 @@ end otf.enhancers["merge cid fonts"] = function(data,filename) -- we can also move the names to data.luatex.names which might -- save us some more memory (at the cost of harder tracing) - if data.subfonts and table.is_empty(data.glyphs) then + if data.subfonts then + if data.glyphs and next(data.glyphs) then + logs.report("load otf","replacing existing glyph table due to subfonts") + end local cidinfo = data.cidinfo local verbose = fonts.verbose if cidinfo.registry then @@ -756,7 +668,7 @@ otf.enhancers["prepare unicode"] = function(data,filename) end end end - -- beware: the indeces table is used to initialize the tfm table + -- beware: the indices table is used to initialize the tfm table for unicode, index in next, mapmap do if not internals[index] then local name = glyphs[index].name @@ -952,6 +864,129 @@ end -- kern: ttf has a table with kerns +--~ otf.enhancers["reorganize kerns"] = function(data,filename) +--~ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes +--~ local mkdone = false +--~ for index, glyph in next, data.glyphs do +--~ if glyph.kerns then +--~ local mykerns = { } +--~ for k,v in next, glyph.kerns do +--~ local vc, vo, vl = v.char, v.off, v.lookup +--~ if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones +--~ local uvc = unicodes[vc] +--~ if not uvc then +--~ if trace_loading then +--~ logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index) +--~ end +--~ else +--~ if type(vl) ~= "table" then +--~ vl = { vl } +--~ end +--~ for l=1,#vl do +--~ local vll = vl[l] +--~ local mkl = mykerns[vll] +--~ if not mkl then +--~ mkl = { } +--~ mykerns[vll] = mkl +--~ end +--~ if type(uvc) == "table" then +--~ for u=1,#uvc do +--~ mkl[uvc[u]] = vo +--~ end +--~ else +--~ mkl[uvc] = vo +--~ end +--~ end +--~ end +--~ end +--~ end +--~ glyph.mykerns = mykerns +--~ glyph.kerns = nil -- saves space and time +--~ mkdone = true +--~ end +--~ end +--~ if trace_loading and mkdone then +--~ logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables") +--~ end +--~ if data.kerns then +--~ if trace_loading then +--~ logs.report("load otf", "removing global 'kern' table") +--~ end +--~ data.kerns = nil +--~ end +--~ local dgpos = data.gpos +--~ if dgpos then +--~ for gp=1,#dgpos do +--~ local gpos = dgpos[gp] +--~ local subtables = gpos.subtables +--~ if subtables then +--~ for s=1,#subtables do +--~ local subtable = subtables[s] +--~ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes +--~ if kernclass then -- the next one is quite slow +--~ for k=1,#kernclass do +--~ local kcl = kernclass[k] +--~ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular +--~ if type(lookups) ~= "table" then +--~ lookups = { lookups } +--~ end +--~ for l=1,#lookups do +--~ local lookup = lookups[l] +--~ -- weird, as maxfirst and maxseconds can have holes +--~ local maxfirsts, maxseconds = getn(firsts), getn(seconds) +--~ if trace_loading then +--~ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds) +--~ end +--~ for fk, fv in next, firsts do +--~ for first in gmatch(fv,"[^ ]+") do +--~ local first_unicode = unicodes[first] +--~ if type(first_unicode) == "number" then +--~ first_unicode = { first_unicode } +--~ end +--~ for f=1,#first_unicode do +--~ local glyph = glyphs[mapmap[first_unicode[f]]] +--~ if glyph then +--~ local mykerns = glyph.mykerns +--~ if not mykerns then +--~ mykerns = { } -- unicode indexed ! +--~ glyph.mykerns = mykerns +--~ end +--~ local lookupkerns = mykerns[lookup] +--~ if not lookupkerns then +--~ lookupkerns = { } +--~ mykerns[lookup] = lookupkerns +--~ end +--~ for sk, sv in next, seconds do +--~ local offset = offsets[(fk-1) * maxseconds + sk] +--~ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk] +--~ for second in gmatch(sv,"[^ ]+") do +--~ local second_unicode = unicodes[second] +--~ if type(second_unicode) == "number" then +--~ lookupkerns[second_unicode] = offset +--~ else +--~ for s=1,#second_unicode do +--~ lookupkerns[second_unicode[s]] = offset +--~ end +--~ end +--~ end +--~ end +--~ elseif trace_loading then +--~ logs.report("load otf", "no glyph data for U+%04X", first_unicode[f]) +--~ end +--~ end +--~ end +--~ end +--~ end +--~ end +--~ subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables." +--~ subtable.kernclass = { } +--~ end +--~ end +--~ end +--~ end +--~ end +--~ end + otf.enhancers["reorganize kerns"] = function(data,filename) local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes local mkdone = false @@ -1004,6 +1039,9 @@ otf.enhancers["reorganize kerns"] = function(data,filename) end local dgpos = data.gpos if dgpos then + local separator = lpeg.P(" ") + local other = ((1 - separator)^0) / unicodes + local splitter = lpeg.Ct(other * (separator * other)^0) for gp=1,#dgpos do local gpos = dgpos[gp] local subtables = gpos.subtables @@ -1011,54 +1049,75 @@ otf.enhancers["reorganize kerns"] = function(data,filename) for s=1,#subtables do local subtable = subtables[s] local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes - if kernclass then + if kernclass then -- the next one is quite slow for k=1,#kernclass do local kcl = kernclass[k] local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular if type(lookups) ~= "table" then lookups = { lookups } end + local split = { } for l=1,#lookups do local lookup = lookups[l] + -- weird, as maxfirst and maxseconds can have holes, first seems to be indexed, seconds starts at 2 local maxfirsts, maxseconds = getn(firsts), getn(seconds) + for _, s in next, firsts do + split[s] = split[s] or lpegmatch(splitter,s) + end + for _, s in next, seconds do + split[s] = split[s] or lpegmatch(splitter,s) + end if trace_loading then logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds) end - for fk, fv in next, firsts do - for first in gmatch(fv,"[^ ]+") do - local first_unicode = unicodes[first] - if type(first_unicode) == "number" then - first_unicode = { first_unicode } + local function do_it(fk,first_unicode) + local glyph = glyphs[mapmap[first_unicode]] + if glyph then + local mykerns = glyph.mykerns + if not mykerns then + mykerns = { } -- unicode indexed ! + glyph.mykerns = mykerns end - for f=1,#first_unicode do - local glyph = glyphs[mapmap[first_unicode[f]]] - if glyph then - local mykerns = glyph.mykerns - if not mykerns then - mykerns = { } -- unicode indexed ! - glyph.mykerns = mykerns - end - local lookupkerns = mykerns[lookup] - if not lookupkerns then - lookupkerns = { } - mykerns[lookup] = lookupkerns - end - for sk, sv in next, seconds do - local offset = offsets[(fk-1) * maxseconds + sk] - --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk] - for second in gmatch(sv,"[^ ]+") do - local second_unicode = unicodes[second] - if type(second_unicode) == "number" then - lookupkerns[second_unicode] = offset - else - for s=1,#second_unicode do - lookupkerns[second_unicode[s]] = offset - end + local lookupkerns = mykerns[lookup] + if not lookupkerns then + lookupkerns = { } + mykerns[lookup] = lookupkerns + end + local baseoffset = (fk-1) * maxseconds + for sk=2,maxseconds do + local sv = seconds[sk] + local offset = offsets[baseoffset + sk] + --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk] + local splt = split[sv] + if splt then + for i=1,#splt do + local second_unicode = splt[i] + if tonumber(second_unicode) then + lookupkerns[second_unicode] = offset + else + for s=1,#second_unicode do + lookupkerns[second_unicode[s]] = offset end end end - elseif trace_loading then - logs.report("load otf", "no glyph data for U+%04X", first_unicode[f]) + end + end + elseif trace_loading then + logs.report("load otf", "no glyph data for U+%04X", first_unicode) + end + end + for fk=1,#firsts do + local fv = firsts[fk] + local splt = split[fv] + if splt then + for i=1,#splt do + local first_unicode = splt[i] + if tonumber(first_unicode) then + do_it(fk,first_unicode) + else + for f=1,#first_unicode do + do_it(fk,first_unicode[f]) + end end end end @@ -1132,10 +1191,31 @@ otf.enhancers["migrate metadata"] = function(data,filename) metadata.charwidth = pfminfo and pfminfo.avgwidth end +local private_math_parameters = { + "FractionDelimiterSize", + "FractionDelimiterDisplayStyleSize", +} + +otf.enhancers["check math parameters"] = function(data,filename) + local mathdata = data.metadata.math + if mathdata then + for m=1,#private_math_parameters do + local pmp = private_math_parameters[m] + if not mathdata[pmp] then + if trace_loading then + logs.report("load otf", "setting math parameter '%s' to 0", pmp) + end + mathdata[pmp] = 0 + end + end + end +end + otf.enhancers["flatten glyph lookups"] = function(data,filename) for k, v in next, data.glyphs do - if v.lookups then - for kk, vv in next, v.lookups do + local lookups = v.lookups + if lookups then + for kk, vv in next, lookups do for kkk=1,#vv do local vvv = vv[kkk] local s = vvv.specification @@ -1185,6 +1265,31 @@ otf.enhancers["flatten glyph lookups"] = function(data,filename) end end +otf.enhancers["simplify glyph lookups"] = function(data,filename) + for k, v in next, data.glyphs do + local lookups = v.lookups + if lookups then + local slookups, mlookups + for kk, vv in next, lookups do + if #vv == 1 then + if not slookups then + slookups = { } + v.slookups = slookups + end + slookups[kk] = vv[1] + else + if not mlookups then + mlookups = { } + v.mlookups = mlookups + end + mlookups[kk] = vv + end + end + v.lookups = nil + end + end +end + otf.enhancers["flatten anchor tables"] = function(data,filename) for k, v in next, data.glyphs do if v.anchors then @@ -1252,10 +1357,12 @@ function otf.features.register(name,default) otf.features.default[name] = default end +-- for context this will become a task handler + function otf.set_features(tfmdata,features) local processes = { } - if not table.is_empty(features) then - local lists = { + if features and next(features) then + local lists = { -- why local fonts.triggers, fonts.processors, fonts.manipulators, @@ -1292,7 +1399,7 @@ function otf.set_features(tfmdata,features) end end end - local fm = fonts.methods[mode] + local fm = fonts.methods[mode] -- todo: zonder node/mode otf/... if fm then local fmotf = fm.otf if fmotf then @@ -1329,14 +1436,14 @@ function otf.otf_to_tfm(specification) --~ print(cache_id) if not tfmdata then local otfdata = otf.load(filename,format,sub,features and features.featurefile) - if not table.is_empty(otfdata) then + if otfdata and next(otfdata) then otfdata.shared = otfdata.shared or { featuredata = { }, anchorhash = { }, initialized = false, } tfmdata = otf.copy_to_tfm(otfdata,cache_id) - if not table.is_empty(tfmdata) then + if tfmdata and next(tfmdata) then tfmdata.unique = tfmdata.unique or { } tfmdata.shared = tfmdata.shared or { } -- combine local shared = tfmdata.shared @@ -1389,6 +1496,11 @@ end -- we cannot share descriptions as virtual fonts might extend them (ok, we could -- use a cache with a hash +fonts.formats.dfont = "truetype" +fonts.formats.ttc = "truetype" +fonts.formats.ttf = "truetype" +fonts.formats.otf = "opentype" + function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many) if data then local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { } @@ -1396,14 +1508,11 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th local unicodes = luatex.unicodes -- names to unicodes local indices = luatex.indices local characters, parameters, math_parameters, descriptions = { }, { }, { }, { } - local tfm = { - characters = characters, - parameters = parameters, - math_parameters = math_parameters, - descriptions = descriptions, - indices = indices, - unicodes = unicodes, - } + local designsize = metadata.designsize or metadata.design_size or 100 + if designsize == 0 then + designsize = 100 + end + local spaceunits = 500 -- indices maps from unicodes to indices for u, i in next, indices do characters[u] = { } -- we need this because for instance we add protruding info and loop over characters @@ -1425,7 +1534,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th local variants = m.horiz_variants if variants then local c = char - for n in variants:gmatch("[^ ]+") do + for n in gmatch(variants,"[^ ]+") do local un = unicodes[n] if un and u ~= un then c.next = un @@ -1437,7 +1546,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th local variants = m.vert_variants if variants then local c = char - for n in variants:gmatch("[^ ]+") do + for n in gmatch(variants,"[^ ]+") do local un = unicodes[n] if un and u ~= un then c.next = un @@ -1445,6 +1554,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th end end c.vert_variants = m.vert_parts + c.vert_italic_correction = m.vert_italic_correction end end local kerns = m.kerns @@ -1455,64 +1565,49 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th end end -- end math - local designsize = metadata.designsize or metadata.design_size or 100 - if designsize == 0 then - designsize = 100 - end - local spaceunits = 500 - tfm.units = metadata.units_per_em or 1000 - -- we need a runtime lookup because of running from cdrom or zip, brrr - tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename - tfm.fullname = metadata.fontname or metadata.fullname - tfm.psname = tfm.fullname - tfm.encodingbytes = 2 - tfm.cidinfo = data.cidinfo - tfm.cidinfo.registry = tfm.cidinfo.registry or "" - tfm.type = "real" - tfm.stretch = 0 -- stretch - tfm.slant = 0 -- slant - tfm.direction = 0 - tfm.boundarychar_label = 0 - tfm.boundarychar = 65536 - tfm.designsize = (designsize/10)*65536 - tfm.spacer = "500 units" - local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash'] + local endash, emdash, space = 0x20, 0x2014, "space" -- unicodes['space'], unicodes['emdash'] if metadata.isfixedpitch then if descriptions[endash] then - spaceunits, tfm.spacer = descriptions[endash].width, "space" + spaceunits, spacer = descriptions[endash].width, "space" end if not spaceunits and descriptions[emdash] then - spaceunits, tfm.spacer = descriptions[emdash].width, "emdash" + spaceunits, spacer = descriptions[emdash].width, "emdash" end if not spaceunits and metadata.charwidth then - spaceunits, tfm.spacer = metadata.charwidth, "charwidth" + spaceunits, spacer = metadata.charwidth, "charwidth" end else if descriptions[endash] then - spaceunits, tfm.spacer = descriptions[endash].width, "space" + spaceunits, spacer = descriptions[endash].width, "space" end if not spaceunits and descriptions[emdash] then - spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2" + spaceunits, spacer = descriptions[emdash].width/2, "emdash/2" end if not spaceunits and metadata.charwidth then - spaceunits, tfm.spacer = metadata.charwidth, "charwidth" + spaceunits, spacer = metadata.charwidth, "charwidth" end end spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr + -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?) + local filename = fonts.tfm.checked_filename(luatex) + local fontname = metadata.fontname + local fullname = metadata.fullname or fontname + local cidinfo = data.cidinfo + local units = metadata.units_per_em or 1000 + -- + cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream + -- parameters.slant = 0 - parameters.space = spaceunits -- 3.333 (cmr10) - parameters.space_stretch = tfm.units/2 -- 500 -- 1.666 (cmr10) - parameters.space_shrink = 1*tfm.units/3 -- 333 -- 1.111 (cmr10) - parameters.x_height = 2*tfm.units/5 -- 400 - parameters.quad = tfm.units -- 1000 - if spaceunits < 2*tfm.units/5 then + parameters.space = spaceunits -- 3.333 (cmr10) + parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10) + parameters.space_shrink = 1*units/3 -- 333 -- 1.111 (cmr10) + parameters.x_height = 2*units/5 -- 400 + parameters.quad = units -- 1000 + if spaceunits < 2*units/5 then -- todo: warning end local italicangle = metadata.italicangle - tfm.ascender = math.abs(metadata.ascent or 0) - tfm.descender = math.abs(metadata.descent or 0) if italicangle then -- maybe also in afm _ - tfm.italicangle = italicangle parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180)) end if metadata.isfixedpitch then @@ -1534,8 +1629,34 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th end end end - -- [6] - return tfm + -- + return { + characters = characters, + parameters = parameters, + math_parameters = math_parameters, + descriptions = descriptions, + indices = indices, + unicodes = unicodes, + type = "real", + direction = 0, + boundarychar_label = 0, + boundarychar = 65536, + designsize = (designsize/10)*65536, + spacer = "500 units", + encodingbytes = 2, + filename = filename, + fontname = fontname, + fullname = fullname, + psname = fontname or fullname, + name = filename or fullname, + units = units, + format = fonts.fontformat(filename,"opentype"), + cidinfo = cidinfo, + ascender = abs(metadata.ascent or 0), + descender = abs(metadata.descent or 0), + spacer = spacer, + italicangle = italicangle, + } else return nil end @@ -1552,6 +1673,7 @@ function tfm.read_from_open_type(specification) local s = specification.size local m = otfdata.metadata.math if m then + -- this will move to a function local f = specification.features if f then local f = f.normal @@ -1579,28 +1701,52 @@ function tfm.read_from_open_type(specification) end end end - tfmtable = tfm.scale(tfmtable,s) - -- here we resolve the name; file can be relocated, so this info is not in the cache - local filename = (otfdata and otfdata.luatex and otfdata.luatex.filename) or specification.filename - if not filename then - -- try to locate anyway and set otfdata.luatex.filename - end - if filename then - tfmtable.encodingbytes = 2 - tfmtable.filename = resolvers.findbinfile(filename,"") or filename - tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname - local order = otfdata and otfdata.metadata.order2 - if order == 0 then - tfmtable.format = 'opentype' - elseif order == 1 then - tfmtable.format = 'truetype' - else - tfmtable.format = specification.format + tfmtable = tfm.scale(tfmtable,s,specification.relativeid) + if tfm.fontname_mode == "specification" then + -- not to be used in context ! + local specname = specification.specification + if specname then + tfmtable.name = specname + if trace_defining then + logs.report("define font","overloaded fontname: '%s'",specname) + end end - tfmtable.name = tfmtable.filename or tfmtable.fullname end fonts.logger.save(tfmtable,file.extname(specification.filename),specification) end --~ print(tfmtable.fullname) return tfmtable end + +-- helpers + +function otf.collect_lookups(otfdata,kind,script,language) + -- maybe store this in the font + local sequences = otfdata.luatex.sequences + if sequences then + local featuremap, featurelist = { }, { } + for s=1,#sequences do + local sequence = sequences[s] + local features = sequence.features + features = features and features[kind] + features = features and (features[script] or features[default] or features[wildcard]) + features = features and (features[language] or features[default] or features[wildcard]) + if features then + local subtables = sequence.subtables + if subtables then + for s=1,#subtables do + local ss = subtables[s] + if not featuremap[s] then + featuremap[ss] = true + featurelist[#featurelist+1] = ss + end + end + end + end + end + if #featurelist > 0 then + return featuremap, featurelist + end + end + return nil, nil +end |