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 | 284 |
1 files changed, 173 insertions, 111 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-otf.lua b/Master/texmf-dist/tex/context/base/font-otf.lua index 36d18a2365f..27a64e91712 100644 --- a/Master/texmf-dist/tex/context/base/font-otf.lua +++ b/Master/texmf-dist/tex/context/base/font-otf.lua @@ -12,6 +12,8 @@ if not modules then modules = { } end modules ['font-otf'] = { -- to_table -> totable -- ascent descent +-- more checking against low level calls of functions + local utf = unicode.utf8 local utfbyte = utf.byte @@ -22,7 +24,7 @@ local getn = table.getn local lpegmatch = lpeg.match local reversed, concat, remove = table.reversed, table.concat, table.remove local ioflush = io.flush -local fastcopy, tohash = table.fastcopy, table.tohash +local fastcopy, tohash, derivetable = table.fastcopy, table.tohash, table.derive local allocate = utilities.storage.allocate local registertracker = trackers.register @@ -47,7 +49,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.730 -- beware: also sync font-mis.lua +otf.version = 2.736 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) local fontdata = fonts.hashes.identifiers @@ -114,15 +116,21 @@ local function showfeatureorder(rawdata,filename) if features then for feature, scripts in next, features do local tt = { } - for script, languages in next, scripts do - local ttt = { } - for language, _ in next, languages do - ttt[#ttt+1] = language + if type(scripts) == "table" then + for script, languages in next, scripts do + local ttt = { } + for language, _ in next, languages do + ttt[#ttt+1] = language + end + tt[#tt+1] = format("[%s: %s]",script,concat(ttt," ")) + end + if trace_loading then + report_otf(" %s: %s",feature,concat(tt," ")) + end + else + if trace_loading then + report_otf(" %s: %s",feature,tostring(scripts)) end - tt[#tt+1] = format("[%s: %s]",script,concat(ttt," ")) - end - if trace_loading then - report_otf(" %s: %s",feature,concat(tt," ")) end end end @@ -291,11 +299,14 @@ end -- patches.register("before","migrate metadata","cambria",function() end) function patches.register(what,where,pattern,action) - local ww = what[where] - if ww then - ww[pattern] = action - else - ww = { [pattern] = action} + local pw = patches[what] + if pw then + local ww = pw[where] + if ww then + ww[pattern] = action + else + pw[where] = { [pattern] = action} + end end end @@ -336,8 +347,8 @@ function otf.load(filename,format,sub,featurefile) local attr = lfs.attributes(name) featurefiles[#featurefiles+1] = { name = name, - size = size, - time = time, + size = attr and attr.size or 0, + time = attr and attr.modification or 0, } end end @@ -420,6 +431,9 @@ function otf.load(filename,format,sub,featurefile) duplicates = { -- alternative unicodes }, + variants = { + -- alternative unicodes (variants) + }, lookuptypes = { }, }, @@ -444,6 +458,7 @@ function otf.load(filename,format,sub,featurefile) if packdata then if cleanup > 0 then collectgarbage("collect") +--~ lua.collectgarbage() end enhance("pack",data,filename,nil) end @@ -451,6 +466,7 @@ function otf.load(filename,format,sub,featurefile) data = containers.write(otf.cache, hash, data) if cleanup > 1 then collectgarbage("collect") +--~ lua.collectgarbage() end stoptiming(data) if elapsedtime then -- not in generic @@ -459,10 +475,12 @@ function otf.load(filename,format,sub,featurefile) fontloader.close(fontdata) -- free memory if cleanup > 3 then collectgarbage("collect") +--~ lua.collectgarbage() end data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one if cleanup > 2 then collectgarbage("collect") +--~ lua.collectgarbage() end else data = nil @@ -499,7 +517,7 @@ local mt = { } actions["prepare tables"] = function(data,filename,raw) - data.properties.italic_correction = false + data.properties.hasitalics = false end actions["add dimensions"] = function(data,filename) @@ -584,7 +602,7 @@ local function somecopy(old) -- fast one end end --- not setting italic_correction and class (when nil) during +-- not setting hasitalics and class (when nil) during -- table cronstruction can save some mem actions["prepare glyphs"] = function(data,filename,raw) @@ -600,6 +618,7 @@ actions["prepare glyphs"] = function(data,filename,raw) local unicodes = resources.unicodes -- name to unicode local indices = resources.indices -- index to unicode local duplicates = resources.duplicates + local variants = resources.variants if rawsubfonts then @@ -699,11 +718,28 @@ actions["prepare glyphs"] = function(data,filename,raw) } local altuni = glyph.altuni if altuni then - local d = { } + local d for i=1,#altuni do - d[#d+1] = altuni[i].unicode + local a = altuni[i] + local u = a.unicode + local v = a.variant + if v then + local vv = variants[v] + if vv then + vv[u] = unicode + else -- xits-math has some: + vv = { [u] = unicode } + variants[v] = vv + end + elseif d then + d[#d+1] = u + else + d = { u } + end + end + if d then + duplicates[unicode] = d end - duplicates[unicode] = d end else report_otf("potential problem: glyph 0x%04X is used but empty",index) @@ -725,9 +761,8 @@ actions["check encoding"] = function(data,filename,raw) local properties = data.properties local unicodes = resources.unicodes -- name to unicode local indices = resources.indices -- index to unicodes - local duplicates = resources.duplicates - -- begin of messy (not needed whwn cidmap) + -- begin of messy (not needed when cidmap) local mapdata = raw.map or { } local unicodetoindex = mapdata and mapdata.map or { } @@ -801,7 +836,6 @@ actions["add duplicates"] = function(data,filename,raw) end end end - end -- class : nil base mark ligature component (maybe we don't need it in description) @@ -812,9 +846,9 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this local resources = data.resources local metadata = data.metadata local properties = data.properties - local italic_correction = false + local hasitalics = false local widths = { } - local marks = { } + local marks = { } -- always present (saves checking) for unicode, description in next, descriptions do local glyph = description.glyph local italic = glyph.italic_correction @@ -824,7 +858,7 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this -- skip else description.italic = italic - italic_correction = true + hasitalics = true end local width = glyph.width widths[width] = (widths[width] or 0) + 1 @@ -837,7 +871,7 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this end end -- flag italic - properties.italic_correction = italic_correction + properties.hasitalics = hasitalics -- flag marks resources.marks = marks -- share most common width for cjk fonts @@ -959,6 +993,29 @@ actions["prepare tounicode"] = function(data,filename,raw) fonts.mappings.addtounicode(data,filename) end +local g_directions = { + gsub_contextchain = 1, + gpos_contextchain = 1, + -- gsub_context = 1, + -- gpos_context = 1, + gsub_reversecontextchain = -1, + gpos_reversecontextchain = -1, +} + +-- Research by Khaled Hosny has demonstrated that the font loader merges +-- regular and AAT features and that these can interfere (especially because +-- we dropped checking for valid features elsewhere. So, we just check for +-- the special flag and drop the feature if such a tag is found. + +local function supported(features) + for i=1,#features do + if features[i].ismac then + return false + end + end + return true +end + actions["reorganize subtables"] = function(data,filename,raw) local resources = data.resources local sequences = { } @@ -971,72 +1028,72 @@ actions["reorganize subtables"] = function(data,filename,raw) if dw then for k=1,#dw do local gk = dw[k] - local typ = gk.type - local chain = - (typ == "gsub_contextchain" or typ == "gpos_contextchain") and 1 or - (typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain") and -1 or 0 - -- - local subtables = gk.subtables - if subtables then - local t = { } - for s=1,#subtables do - t[s] = subtables[s].name + local features = gk.features +-- if features and supported(features) then + if not features or supported(features) then -- not always features ! + local typ = gk.type + local chain = g_directions[typ] or 0 + local subtables = gk.subtables + if subtables then + local t = { } + for s=1,#subtables do + t[s] = subtables[s].name + end + subtables = t end - subtables = t - end - local flags, markclass = gk.flags, nil - if flags then - local t = { -- forcing false packs nicer - (flags.ignorecombiningmarks and "mark") or false, - (flags.ignoreligatures and "ligature") or false, - (flags.ignorebaseglyphs and "base") or false, - flags.r2l or false, - } - markclass = flags.mark_class - if markclass then - markclass = resources.markclasses[markclass] + local flags, markclass = gk.flags, nil + if flags then + local t = { -- forcing false packs nicer + (flags.ignorecombiningmarks and "mark") or false, + (flags.ignoreligatures and "ligature") or false, + (flags.ignorebaseglyphs and "base") or false, + flags.r2l or false, + } + markclass = flags.mark_class + if markclass then + markclass = resources.markclasses[markclass] + end + flags = t end - flags = t - end - -- - local name = gk.name - -- - local features = gk.features - if features then - -- scripts, tag, ismac - local f = { } - for i=1,#features do - local df = features[i] - local tag = strip(lower(df.tag)) - local ft = f[tag] if not ft then ft = {} f[tag] = ft end - local dscripts = df.scripts - for i=1,#dscripts do - local d = dscripts[i] - local languages = d.langs - local script = strip(lower(d.script)) - local fts = ft[script] if not fts then fts = {} ft[script] = fts end - for i=1,#languages do - fts[strip(lower(languages[i]))] = true + -- + local name = gk.name + -- + if features then + -- scripts, tag, ismac + local f = { } + for i=1,#features do + local df = features[i] + local tag = strip(lower(df.tag)) + local ft = f[tag] if not ft then ft = {} f[tag] = ft end + local dscripts = df.scripts + for i=1,#dscripts do + local d = dscripts[i] + local languages = d.langs + local script = strip(lower(d.script)) + local fts = ft[script] if not fts then fts = {} ft[script] = fts end + for i=1,#languages do + fts[strip(lower(languages[i]))] = true + end end end + sequences[#sequences+1] = { + type = typ, + chain = chain, + flags = flags, + name = name, + subtables = subtables, + markclass = markclass, + features = f, + } + else + lookups[name] = { + type = typ, + chain = chain, + flags = flags, + subtables = subtables, + markclass = markclass, + } end - sequences[#sequences+1] = { - type = typ, - chain = chain, - flags = flags, - name = name, - subtables = subtables, - markclass = markclass, - features = f, - } - else - lookups[name] = { - type = typ, - chain = chain, - flags = flags, - subtables = subtables, - markclass = markclass, - } end end end @@ -1077,19 +1134,20 @@ end local function t_hashed(t,cache) if t then - local h = { } + local ht = { } for i=1,#t do local ti = t[i] - local h = cache[ti] - if not h then - h = { } + local tih = cache[ti] + if not tih then + tih = { } for i=1,#ti do - h[ti] = true + tih[ti[i]] = true end + cache[ti] = tih end - cache[ti] = h + ht[i] = tih end - return h + return ht else return nil end @@ -1173,7 +1231,7 @@ actions["reorganize lookups"] = function(data,filename,raw) for i=1,#current do current[i] = current_class[current[i]] or { } if lookups and not lookups[i] then - lookups[i] = false + lookups[i] = false -- e.g. we can have two lookups and one replacement end end rule.current = t_hashed(current,h_cache) @@ -1270,8 +1328,6 @@ actions["reorganize lookups"] = function(data,filename,raw) end end --- to be checked italic_correction - local function check_variants(unicode,the_variants,splitter,unicodes) local variants = the_variants.variants if variants then -- use splitter @@ -1671,9 +1727,9 @@ local function copytotfm(data,cache_id) if data then local metadata = data.metadata local resources = data.resources - local properties = table.derive(data.properties) - local descriptions = table.derive(data.descriptions) - local goodies = table.derive(data.goodies) + local properties = derivetable(data.properties) + local descriptions = derivetable(data.descriptions) + local goodies = derivetable(data.goodies) local characters = { } local parameters = { } local mathparameters = { } @@ -1799,6 +1855,11 @@ local function copytotfm(data,cache_id) local fullname = metadata.fullname or fontname local units = metadata.units_per_em or 1000 -- + if units == 0 then -- catch bugs in fonts + units = 1000 + metadata.units_per_em = 1000 + end + -- parameters.slant = 0 parameters.space = spaceunits -- 3.333 (cmr10) parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10) @@ -1884,9 +1945,9 @@ local function otftotfm(specification) tfmdata.shared = shared end shared.rawdata = rawdata - shared.features = features -- default + -- shared.features = features -- default shared.dynamics = { } - shared.processes = { } + -- shared.processes = { } tfmdata.changed = { } shared.features = features shared.processes = otf.setfeatures(tfmdata,features) @@ -1905,7 +1966,8 @@ local function read_from_otf(specification) tfmdata.properties.sub = specification.sub -- tfmdata = constructors.scale(tfmdata,specification) - constructors.applymanipulators("otf",tfmdata,specification.features.normal,trace_features,report_otf) + local allfeatures = tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf) constructors.setname(tfmdata,specification) -- only otf? fonts.loggers.register(tfmdata,file.extname(specification.filename),specification) end @@ -1971,15 +2033,15 @@ local function check_otf(forced,specification,suffix,what) if forced then name = file.addsuffix(name,suffix,true) end - local fullname, tfmdata = findbinfile(name,suffix) or "", nil -- one shot + local fullname = findbinfile(name,suffix) or "" if fullname == "" then - fullname = fonts.names.getfilename(name,suffix) + fullname = fonts.names.getfilename(name,suffix) or "" end if fullname ~= "" then - specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then - tfmdata = read_from_otf(specification) -- we need to do it for all matches / todo + specification.filename = fullname + specification.format = what + return read_from_otf(specification) end - return tfmdata end local function opentypereader(specification,suffix,what) |