diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua | 377 |
1 files changed, 262 insertions, 115 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua index 0dc4eca5b86..208ad50a873 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua @@ -6,9 +6,13 @@ if not modules then modules = { } end modules ['font-map'] = { license = "see context related readme files" } -local match, format, find, concat = string.match, string.format, string.find, table.concat +local utf = unicode.utf8 +local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower +local lpegmatch = lpeg.match +local utfbyte = utf.byte -local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) +local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) +local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end) local ctxcatcodes = tex and tex.ctxcatcodes @@ -18,116 +22,10 @@ of obsolete. Some code may move to runtime or auxiliary modules.</p> <p>The name to unciode related code will stay of course.</p> --ldx]]-- -fonts = fonts or { } -fonts.map = fonts.map or { } -fonts.map.data = fonts.map.data or { } -fonts.map.encodings = fonts.map.encodings or { } -fonts.map.done = fonts.map.done or { } -fonts.map.loaded = fonts.map.loaded or { } -fonts.map.direct = fonts.map.direct or { } -fonts.map.line = fonts.map.line or { } - -function fonts.map.line.pdfmapline(tag,str) - return "\\loadmapline[" .. tag .. "][" .. str .. "]" -end - -function fonts.map.line.pdftex(e) -- so far no combination of slant and stretch - if e.name and e.fontfile then - local fullname = e.fullname or "" - if e.slant and e.slant ~= 0 then - if e.encoding then - return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile)) - else - return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile)) - end - elseif e.stretch and e.stretch ~= 1 and e.stretch ~= 0 then - if e.encoding then - return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.stretch,e.encoding,e.fontfile)) - else - return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.stretch,e.fontfile)) - end - else - if e.encoding then - return fonts.map.line.pdfmapline("=",format('%s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile)) - else - return fonts.map.line.pdfmapline("=",format('%s %s <%s',e.name,fullname,e.fontfile)) - end - end - else - return nil - end -end - -function fonts.map.flush(backend) -- will also erase the accumulated data - local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex - for _, e in pairs(fonts.map.data) do - tex.sprint(ctxcatcodes,flushline(e)) - end - fonts.map.data = { } -end - -fonts.map.line.dvips = fonts.map.line.pdftex -fonts.map.line.dvipdfmx = function() end - -function fonts.map.convert_entries(filename) - if not fonts.map.loaded[filename] then - fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings) - fonts.map.loaded[filename] = true - end -end - -function fonts.map.load_file(filename, entries, encodings) - entries = entries or { } - encodings = encodings or { } - local f = io.open(filename) - if f then - local data = f:read("*a") - if data then - for line in gmatch(data,"(.-)[\n\t]") do - if find(line,"^[%#%%%s]") then - -- print(line) - else - local stretch, slant, name, fullname, fontfile, encoding - line = line:gsub('"(.+)"', function(s) - stretch = find(s,'"([^"]+) ExtendFont"') - slant = find(s,'"([^"]+) SlantFont"') - return "" - end) - if not name then - -- name fullname encoding fontfile - name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$") - end - if not name then - -- name fullname (flag) fontfile encoding - name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$") - end - if not name then - -- name fontfile - name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$") - end - if name then - if encoding == "" then encoding = nil end - entries[name] = { - name = name, -- handy - fullname = fullname, - encoding = encoding, - fontfile = fontfile, - slant = tonumber(slant), - stretch = tonumber(stretch) - } - encodings[name] = encoding - elseif line ~= "" then - -- print(line) - end - end - end - end - f:close() - end - return entries, encodings -end +fonts = fonts or { } +fonts.map = fonts.map or { } -function fonts.map.load_lum_table(filename) +local function load_lum_table(filename) -- will move to font goodies local lumname = file.replacesuffix(file.basename(filename),"lum") local lumfile = resolvers.find_file(lumname,"map") or "" if lumfile ~= "" and lfs.isfile(lumfile) then @@ -153,7 +51,7 @@ local parser = unicode + ucode + index local parsers = { } -function fonts.map.make_name_parser(str) +local function make_name_parser(str) if not str or str == "" then return parser else @@ -169,7 +67,7 @@ end --~ local parser = fonts.map.make_name_parser("Japan1") --~ local parser = fonts.map.make_name_parser() --~ local function test(str) ---~ local b, a = parser:match(str) +--~ local b, a = lpegmatch(parser,str) --~ print((a and table.serialize(b)) or b) --~ end --~ test("a.sc") @@ -180,7 +78,7 @@ end --~ test("index1234") --~ test("Japan1.123") -function fonts.map.tounicode16(unicode) +local function tounicode16(unicode) if unicode < 0x10000 then return format("%04X",unicode) else @@ -188,7 +86,7 @@ function fonts.map.tounicode16(unicode) end end -function fonts.map.tounicode16sequence(unicodes) +local function tounicode16sequence(unicodes) local t = { } for l=1,#unicodes do local unicode = unicodes[l] @@ -221,3 +119,252 @@ end --~ return s --~ end +fonts.map.load_lum_table = load_lum_table +fonts.map.make_name_parser = make_name_parser +fonts.map.tounicode16 = tounicode16 +fonts.map.tounicode16sequence = tounicode16sequence + +local separator = lpeg.S("_.") +local other = lpeg.C((1 - separator)^1) +local ligsplitter = lpeg.Ct(other * (separator * other)^0) + +--~ print(table.serialize(lpegmatch(ligsplitter,"this"))) +--~ print(table.serialize(lpegmatch(ligsplitter,"this.that"))) +--~ print(table.serialize(lpegmatch(ligsplitter,"japan1.123"))) +--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more"))) +--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more.that"))) + +fonts.map.add_to_unicode = function(data,filename) + local unicodes = data.luatex and data.luatex.unicodes + if not unicodes then + return + end + -- we need to move this code + unicodes['space'] = unicodes['space'] or 32 + unicodes['hyphen'] = unicodes['hyphen'] or 45 + unicodes['zwj'] = unicodes['zwj'] or 0x200D + unicodes['zwnj'] = unicodes['zwnj'] or 0x200C + -- 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 = 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 lower(usedmap) + usedmap = usedmap and fonts.cid.map[usedmap] + if usedmap then + oparser = usedmap and make_name_parser(cidinfo.ordering) + cidnames = usedmap.names + cidcodes = usedmap.unicodes + end + uparser = make_name_parser() + local aglmap = fonts.map and fonts.map.agl_to_unicode + 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]) or (aglmap and aglmap[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 = lpegmatch(oparser,name) + if foundindex then + unicode = cidcodes[foundindex] -- name to number + if unicode then + originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 + else + local reference = cidnames[foundindex] -- number to name + if reference then + local foundindex = lpegmatch(oparser,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 = lpegmatch(uparser,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 = lpegmatch(ligsplitter,name) + local nplit = (split and #split) or 0 + if nplit == 0 then + -- skip + elseif nplit == 1 then + local base = split[1] + unicode = unicodes[base] or (aglmap and aglmap[base]) + 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 t = { } + for l=1,nplit do + local base = split[l] + local u = unicodes[base] or (aglmap and aglmap[base]) + if not u then + break + elseif type(u) == "table" then + t[#t+1] = u[1] + else + t[#t+1] = u + end + end + if #t > 0 then -- done then + originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true + end + end + end + -- last resort + if not unicode then + local foundcodes, multiple = lpegmatch(uparser,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 + +-- the following is sort of obsolete +-- +-- fonts.map.data = fonts.map.data or { } +-- fonts.map.encodings = fonts.map.encodings or { } +-- fonts.map.loaded = fonts.map.loaded or { } +-- fonts.map.line = fonts.map.line or { } +-- +-- function fonts.map.line.pdftex(e) +-- if e.name and e.fontfile then +-- local fullname = e.fullname or "" +-- if e.slant and e.slant ~= 0 then +-- if e.encoding then +-- pdf.mapline(format('= %s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile))) +-- else +-- pdf.mapline(format('= %s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile))) +-- end +-- elseif e.extend and e.extend ~= 1 and e.extend ~= 0 then +-- if e.encoding then +-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.extend,e.encoding,e.fontfile))) +-- else +-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s',e.name,fullname,e.extend,e.fontfile))) +-- end +-- else +-- if e.encoding then +-- pdf.mapline(format('= %s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile))) +-- else +-- pdf.mapline(format('= %s %s <%s',e.name,fullname,e.fontfile))) +-- end +-- end +-- else +-- return nil +-- end +-- end +-- +-- function fonts.map.flush(backend) -- will also erase the accumulated data +-- local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex +-- for _, e in pairs(fonts.map.data) do +-- flushline(e) +-- end +-- fonts.map.data = { } +-- end +-- +-- fonts.map.line.dvips = fonts.map.line.pdftex +-- fonts.map.line.dvipdfmx = function() end +-- +-- function fonts.map.convert_entries(filename) +-- if not fonts.map.loaded[filename] then +-- fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings) +-- fonts.map.loaded[filename] = true +-- end +-- end +-- +-- function fonts.map.load_file(filename, entries, encodings) +-- entries = entries or { } +-- encodings = encodings or { } +-- local f = io.open(filename) +-- if f then +-- local data = f:read("*a") +-- if data then +-- for line in gmatch(data,"(.-)[\n\t]") do +-- if find(line,"^[%#%%%s]") then +-- -- print(line) +-- else +-- local extend, slant, name, fullname, fontfile, encoding +-- line = gsub(line,'"(.+)"', function(s) +-- extend = find(s,'"([^"]+) ExtendFont"') +-- slant = find(s,'"([^"]+) SlantFont"') +-- return "" +-- end) +-- if not name then +-- -- name fullname encoding fontfile +-- name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$") +-- end +-- if not name then +-- -- name fullname (flag) fontfile encoding +-- name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$") +-- end +-- if not name then +-- -- name fontfile +-- name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$") +-- end +-- if name then +-- if encoding == "" then encoding = nil end +-- entries[name] = { +-- name = name, -- handy +-- fullname = fullname, +-- encoding = encoding, +-- fontfile = fontfile, +-- slant = tonumber(slant), +-- extend = tonumber(extend) +-- } +-- encodings[name] = encoding +-- elseif line ~= "" then +-- -- print(line) +-- end +-- end +-- end +-- end +-- f:close() +-- end +-- return entries, encodings +-- end |