2020-07-04 06:27:30 +02:00
|
|
|
font.read_tfm = require'luametalatex-font-tfm'
|
2020-06-19 23:49:23 +02:00
|
|
|
local read_vf = require'luametalatex-font-vf'
|
2020-07-04 06:27:30 +02:00
|
|
|
font.read_vf = read_vf
|
2020-06-19 23:49:23 +02:00
|
|
|
local fontmap = require'luametalatex-pdf-font-map'.fontmap
|
2020-08-13 22:24:13 +02:00
|
|
|
local callbacks = require'luametalatex-callbacks'
|
2020-06-19 23:49:23 +02:00
|
|
|
|
|
|
|
local old_font_define = font.define
|
2020-07-07 04:54:27 +02:00
|
|
|
local old_addcharacters = font.addcharacters
|
2020-06-19 23:49:23 +02:00
|
|
|
|
2020-07-15 16:36:11 +02:00
|
|
|
require'luametalatex-pdf-font-map'.mapfile'pdftex.map'
|
2020-06-19 23:49:23 +02:00
|
|
|
|
|
|
|
local all_fonts = {}
|
|
|
|
font.fonts = all_fonts
|
|
|
|
function font.getfont(id)
|
|
|
|
return all_fonts[id]
|
|
|
|
end
|
2021-11-20 15:39:43 +01:00
|
|
|
-- Currently either nil or true, false (defined but not yet frozen) isn't implemented right now
|
|
|
|
function font.frozen(id)
|
|
|
|
return all_fonts[id] and true
|
|
|
|
end
|
2020-06-19 23:49:23 +02:00
|
|
|
|
|
|
|
local fontextensions = {
|
2020-07-15 16:36:11 +02:00
|
|
|
ttf = "truetype",
|
|
|
|
otf = "opentype",
|
|
|
|
pfb = "type1",
|
2020-06-19 23:49:23 +02:00
|
|
|
}
|
|
|
|
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
|
2020-07-02 14:18:12 +02:00
|
|
|
local reencode = name * space * 'ReEncodeFont'
|
2020-06-19 23:49:23 +02:00
|
|
|
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
|
2020-07-08 22:20:08 +02:00
|
|
|
if encodingbytes == 1 and f.type ~= 'virtual' and f.format ~= 'type3node' then
|
2020-06-19 23:49:23 +02:00
|
|
|
-- map file lookup
|
|
|
|
local entry = fontmap[f.name]
|
|
|
|
if entry then
|
|
|
|
local filename = entry[3]
|
2020-07-15 16:36:11 +02:00
|
|
|
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))
|
2020-06-19 23:49:23 +02:00
|
|
|
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
|
2020-08-13 22:24:13 +02:00
|
|
|
f.id = assert(callbacks.define_font(f.name, f.size or -1000))
|
2020-06-19 23:49:23 +02:00
|
|
|
elseif f.id == 0 then
|
|
|
|
f.id = id
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return id
|
|
|
|
end
|
2020-07-07 04:54:27 +02:00
|
|
|
|
|
|
|
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
|
2020-08-13 22:24:13 +02:00
|
|
|
f.id = assert(callback.define_font(f.name, f.size or -1000))
|
2020-07-07 04:54:27 +02:00
|
|
|
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
|
2020-07-08 22:20:08 +02:00
|
|
|
-- texio.write_nl'Overwriting existing character. Here be dragons'
|
2020-07-07 04:54:27 +02:00
|
|
|
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
|