if not modules then modules = { } end modules ['font-map'] = { 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 match, format, find, concat, gsub = string.match, string.format, string.find, table.concat, string.gsub local lpegmatch = lpeg.match local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) local ctxcatcodes = tex and tex.ctxcatcodes --[[ldx--

Eventually this code will disappear because map files are kind of obsolete. Some code may move to runtime or auxiliary modules.

The name to unciode related code will stay of course.

--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 extend 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.extend and e.extend ~= 1 and e.extend ~= 0 then if e.encoding then return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.extend,e.encoding,e.fontfile)) else return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.extend,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 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 function fonts.map.load_lum_table(filename) local lumname = file.replacesuffix(file.basename(filename),"lum") local lumfile = resolvers.find_file(lumname,"map") or "" if lumfile ~= "" and lfs.isfile(lumfile) then if trace_loading or trace_unimapping then logs.report("load otf","enhance: loading %s ",lumfile) end lumunic = dofile(lumfile) return lumunic, lumfile end end local hex = lpeg.R("AF","09") local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end local hexsix = (hex^1) / function(s) return tonumber(s,16) end local dec = (lpeg.R("09")^1) / tonumber local period = lpeg.P(".") local unicode = lpeg.P("uni") * (hexfour * (period + lpeg.P(-1)) * lpeg.Cc(false) + lpeg.Ct(hexfour^1) * lpeg.Cc(true)) local ucode = lpeg.P("u") * (hexsix * (period + lpeg.P(-1)) * lpeg.Cc(false) + lpeg.Ct(hexsix ^1) * lpeg.Cc(true)) local index = lpeg.P("index") * dec * lpeg.Cc(false) local parser = unicode + ucode + index local parsers = { } function fonts.map.make_name_parser(str) if not str or str == "" then return parser else local p = parsers[str] if not p then p = lpeg.P(str) * period * dec * lpeg.Cc(false) parsers[str] = p end return p end end --~ local parser = fonts.map.make_name_parser("Japan1") --~ local parser = fonts.map.make_name_parser() --~ local function test(str) --~ local b, a = lpegmatch(parser,str) --~ print((a and table.serialize(b)) or b) --~ end --~ test("a.sc") --~ test("a") --~ test("uni1234") --~ test("uni1234.xx") --~ test("uni12349876") --~ test("index1234") --~ test("Japan1.123") function fonts.map.tounicode16(unicode) if unicode < 0x10000 then return format("%04X",unicode) else return format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) end end function fonts.map.tounicode16sequence(unicodes) local t = { } for l=1,#unicodes do local unicode = unicodes[l] if unicode < 0x10000 then t[l] = format("%04X",unicode) else t[l] = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) end end return concat(t) end --~ This is quite a bit faster but at the cost of some memory but if we --~ do this we will also use it elsewhere so let's not follow this route --~ now. I might use this method in the plain variant (no caching there) --~ but then I need a flag that distinguishes between code branches. --~ --~ local cache = { } --~ --~ function fonts.map.tounicode16(unicode) --~ local s = cache[unicode] --~ if not s then --~ if unicode < 0x10000 then --~ s = format("%04X",unicode) --~ else --~ s = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) --~ end --~ cache[unicode] = s --~ end --~ return s --~ end