luametalatex/luametalatex-font-resolve.lua

143 lines
4.1 KiB
Lua

font.read_tfm = require'luametalatex-font-tfm'
local read_vf = require'luametalatex-font-vf'
font.read_vf = read_vf
local fontmap = require'luametalatex-pdf-font-map'.fontmap
local callback_find = callback.find
local old_font_define = font.define
local old_addcharacters = font.addcharacters
require'luametalatex-pdf-font-map'.mapfile'pdftex.map'
local all_fonts = {}
font.fonts = all_fonts
function font.getfont(id)
return all_fonts[id]
end
local fontextensions = {
ttf = "truetype",
otf = "opentype",
pfb = "type1",
}
fontextensions.cff = fontextensions.otf
local fontformats = {
fontextensions.pfb, fontextensions.otf, fontextensions.ttf,
}
local special_parser do
local l = lpeg or require'lpeg'
local space = l.S' '^0
local name = (1-l.P' ')^1
local reencode = name * space * 'ReEncodeFont'
local digit = l.R'09'
local number = digit^1 * ('.' * digit^0) + '.' * digit^1/tonumber
local milli_stmt = number * space * ('SlantFont' * l.Cc'slant' + 'ExtendFont' * l.Cc'extend') / function(n, k)
return k, (n*1000 + .5)//1
end
special_parser = l.Cf(l.Carg(1) * (space * (reencode + milli_stmt))^0 * space * -1, rawset)
end
function font.define(f)
if (f.type or "unknown") == "unknown" then
local vf = read_vf(f.name, f.size)
if vf then
f.type = 'virtual'
f.fonts = vf.fonts
local realchars = f.characters
for cp, char in next, vf.characters do
assert(realchars[cp]).commands = char.commands
end
else
f.type = 'real'
end
end
local format = f.format or "unknown"
local encodingbytes = f.encodingbytes or (f.format:sub(5) == "type" and 2 or 1)
f.encodingbytes = encodingbytes
if encodingbytes == 1 and f.type ~= 'virtual' and f.format ~= 'type3node' then
-- map file lookup
local entry = fontmap[f.name]
if entry then
local filename = entry[3]
local format
if f.format == 'unknown' then
f.format = filename and filename:sub(-4, -4) == '.' and fontextensions[filename:sub(-3, -1)] or 'type1'
end
f.filename = filename
f.encoding = entry[4]
if entry[5] then
assert(special_parser:match(entry[5], 1, f))
end
else
f.format = "type3"
end
end
local id = old_font_define(f)
all_fonts[id] = f
if f.fonts then
for i, f in next, f.fonts do
if not f.id then
f.id = assert(callback_find'define_font'(f.name, f.size or -1000))
elseif f.id == 0 then
f.id = id
end
end
end
return id
end
function font.addcharacters(fid, newdir)
old_addcharacters(fid, newdir) -- The easy part, the remaining stuff gets crazy
local fontdir = assert(all_fonts[fid], 'addcharacters expects an existing font')
local fonts_map
if newdir.fonts then -- FIXME: Handle default fonts table
if fontdir.fonts then
fonts_map = {}
for i,f in next, newdir.fonts do
if not f.id then
f.id = assert(callback_find'define_font'(f.name, f.size or -1000))
elseif f.id == 0 then
f.id = fid
end
for j,ff in next, fontdir.fonts do
if ff.id == f.id then
fonts_map[i] = j
goto FONT_MAPPING_SET -- A typical for ... do ... else ... end implemented using goto.
end
end
-- NOT FOUND, so add it
local new_f = #fontdir.fonts + 1
fontdir.fonts[new_f] = f
fonts_map[i] = f
::FONT_MAPPING_SET::
end
else
fontdir.fonts = newdir.fonts
end
end
for cp, glyph in next, newdir do
local existing = fontdir[cp]
if existing ~= glyph then
if existing then
-- texio.write_nl'Overwriting existing character. Here be dragons'
end
end
if glyph.commands then
local font_seen
for _, cmd in ipairs(glyph.commands) do
if cmd[1] == 'font' then
font_seen = true
cmd[2] = fonts_map[cmd[2]]
elseif cmd[1] == 'slot' then
font_seen = true
cmd[2] = fonts_map[cmd[2]]
elseif not font_seen and cmd[1] == 'char' then
font_seen = true
cmd[1], cmd[2], cmd[3] = 'slot', fonts_map[1], cmd[2]
end
end
end
end
end