summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-afm.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-afm.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-afm.lua941
1 files changed, 523 insertions, 418 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-afm.lua b/Master/texmf-dist/tex/context/base/font-afm.lua
index fd931547233..81b47a2698c 100644
--- a/Master/texmf-dist/tex/context/base/font-afm.lua
+++ b/Master/texmf-dist/tex/context/base/font-afm.lua
@@ -17,18 +17,27 @@ where we handles font encodings. Eventually font encoding goes
away.</p>
--ldx]]--
-fonts = fonts or { }
-fonts.afm = fonts.afm or { }
-fonts.afm.version = 1.26 -- incrementing this number one up will force a re-cache
-fonts.afm.syncspace = true -- when true, nicer stretch values
-fonts.afm.enhance_data = true -- best leave this set to true
-fonts.afm.trace_features = false
-fonts.afm.features = { }
-fonts.afm.features.aux = { }
-fonts.afm.features.data = { }
-fonts.afm.features.list = { }
-fonts.afm.features.default = { }
-fonts.afm.cache = containers.define("fonts", "afm", fonts.afm.version, true)
+local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
+local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
+local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end)
+
+local format, match, gmatch, lower = string.format, string.match, string.gmatch, string.lower
+
+fonts = fonts or { }
+fonts.afm = fonts.afm or { }
+
+local afm = fonts.afm
+local tfm = fonts.tfm
+
+afm.version = 1.400 -- incrementing this number one up will force a re-cache
+afm.syncspace = true -- when true, nicer stretch values
+afm.enhance_data = true -- best leave this set to true
+afm.features = { }
+afm.features.aux = { }
+afm.features.data = { }
+afm.features.list = { }
+afm.features.default = { }
+afm.cache = containers.define("fonts", "afm", afm.version, true)
--[[ldx--
<p>We start with the basic reader which we give a name similar to the
@@ -51,199 +60,197 @@ built in <l n='tfm'/> and <l n='otf'/> reader.</p>
--~ Comment DELIM 2390 1010
--~ Comment AXISHEIGHT 250
-do
-
- local c = lpeg.P("Comment")
- local s = lpeg.S(" \t")
- local l = lpeg.S("\n\r")
- local w = lpeg.C((1 - l)^1)
- local n = lpeg.C((lpeg.R("09") + lpeg.S("."))^1) / tonumber * s^0
-
- local fd = { }
-
- local pattern = ( c * s^1 * (
- ("CODINGSCHEME" * s^1 * w ) / function(a) end +
- ("DESIGNSIZE" * s^1 * n * w ) / function(a) fd[ 1] = a end +
- ("CHECKSUM" * s^1 * n * w ) / function(a) fd[ 2] = a end +
- ("SPACE" * s^1 * n * "plus" * n * "minus" * n) / function(a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
- ("QUAD" * s^1 * n ) / function(a) fd[ 6] = a end +
- ("EXTRASPACE" * s^1 * n ) / function(a) fd[ 7] = a end +
- ("NUM" * s^1 * n * n * n ) / function(a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
- ("DENOM" * s^1 * n * n ) / function(a,b ) fd[11], fd[12] = a, b end +
- ("SUP" * s^1 * n * n * n ) / function(a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
- ("SUB" * s^1 * n * n ) / function(a,b) fd[16], fd[17] = a, b end +
- ("SUPDROP" * s^1 * n ) / function(a) fd[18] = a end +
- ("SUBDROP" * s^1 * n ) / function(a) fd[19] = a end +
- ("DELIM" * s^1 * n * n ) / function(a,b) fd[20], fd[21] = a, b end +
- ("AXISHEIGHT" * s^1 * n ) / function(a) fd[22] = a end +
- (1-l)^0
- ) + (1-c)^1)^0
-
- function fonts.afm.scan_comment(str)
- fd = { }
- pattern:match(str)
- return fd
- end
-
+local c = lpeg.P("Comment")
+local s = lpeg.S(" \t")
+local l = lpeg.S("\n\r")
+local w = lpeg.C((1 - l)^1)
+local n = lpeg.C((lpeg.R("09") + lpeg.S("."))^1) / tonumber * s^0
+
+local fd = { }
+
+local pattern = ( c * s^1 * (
+ ("CODINGSCHEME" * s^1 * w ) / function(a) end +
+ ("DESIGNSIZE" * s^1 * n * w ) / function(a) fd[ 1] = a end +
+ ("CHECKSUM" * s^1 * n * w ) / function(a) fd[ 2] = a end +
+ ("SPACE" * s^1 * n * "plus" * n * "minus" * n) / function(a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
+ ("QUAD" * s^1 * n ) / function(a) fd[ 6] = a end +
+ ("EXTRASPACE" * s^1 * n ) / function(a) fd[ 7] = a end +
+ ("NUM" * s^1 * n * n * n ) / function(a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
+ ("DENOM" * s^1 * n * n ) / function(a,b ) fd[11], fd[12] = a, b end +
+ ("SUP" * s^1 * n * n * n ) / function(a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
+ ("SUB" * s^1 * n * n ) / function(a,b) fd[16], fd[17] = a, b end +
+ ("SUPDROP" * s^1 * n ) / function(a) fd[18] = a end +
+ ("SUBDROP" * s^1 * n ) / function(a) fd[19] = a end +
+ ("DELIM" * s^1 * n * n ) / function(a,b) fd[20], fd[21] = a, b end +
+ ("AXISHEIGHT" * s^1 * n ) / function(a) fd[22] = a end +
+ (1-l)^0
+) + (1-c)^1)^0
+
+local function scan_comment(str)
+ fd = { }
+ pattern:match(str)
+ return fd
end
-do
-
- -- On a rainy day I will rewrite this in lpeg ...
-
- local keys = { }
-
- function keys.FontName (data,line) data.fullname = line:strip() end
- function keys.ItalicAngle (data,line) data.italicangle = tonumber (line) end
- function keys.IsFixedPitch(data,line) data.isfixedpitch = toboolean(line,true) end
- function keys.CharWidth (data,line) data.charwidth = tonumber (line) end
- function keys.XHeight (data,line) data.xheight = tonumber (line) end
- function keys.Descender (data,line) data.descender = tonumber (line) end
- function keys.Ascender (data,line) data.ascender = tonumber (line) end
- function keys.Comment (data,line)
- -- Comment DesignSize 12 (pts)
- -- Comment TFM designsize: 12 (in points)
- line = line:lower()
- local designsize = line:match("designsize[^%d]*(%d+)")
- if designsize then data.designsize = tonumber(designsize) end
- end
+-- On a rainy day I will rewrite this in lpeg ...
+
+local keys = { }
+
+function keys.FontName (data,line) data.metadata.fullname = line:strip() end
+function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end
+function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end
+function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end
+function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end
+function keys.Descender (data,line) data.metadata.descender = tonumber (line) end
+function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end
+function keys.Comment (data,line)
+ -- Comment DesignSize 12 (pts)
+ -- Comment TFM designsize: 12 (in points)
+ line = lower(line)
+ local designsize = match(line,"designsize[^%d]*(%d+)")
+ if designsize then data.metadata.designsize = tonumber(designsize) end
+end
- local function get_charmetrics(data,charmetrics,vector)
- local characters = data.characters
- local chr, str, ind = { }, "", 0
- for k,v in charmetrics:gmatch("([%a]+) +(.-) *;") do
- if k == 'C' then
- if str ~= "" then characters[str] = chr end
- chr = { }
- str = ""
- v = tonumber(v)
- if v < 0 then
- ind = ind + 1
- else
- ind = v
- end
- chr.index = ind
- elseif k == 'WX' then
- chr.width = v
- elseif k == 'N' then
- str = v
- elseif k == 'B' then
- local llx, lly, urx, ury = v:match("^ *(.-) +(.-) +(.-) +(.-)$")
- chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
- elseif k == 'L' then
- local plus, becomes = v:match("^(.-) +(.-)$")
- if not chr.ligatures then chr.ligatures = { } end
- chr.ligatures[plus] = becomes
+local function get_charmetrics(data,charmetrics,vector)
+ local characters = data.characters
+ local chr, str, ind = { }, "", 0
+ for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
+ if k == 'C' then
+ if str ~= "" then characters[str] = chr end
+ chr = { }
+ str = ""
+ v = tonumber(v)
+ if v < 0 then
+ ind = ind + 1
+ else
+ ind = v
end
- end
- if str ~= "" then
- characters[str] = chr
+ chr.index = ind
+ elseif k == 'WX' then
+ chr.width = v
+ elseif k == 'N' then
+ str = v
+ elseif k == 'B' then
+ local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
+ chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
+ elseif k == 'L' then
+ local plus, becomes = match(v,"^(.-) +(.-)$")
+ if not chr.ligatures then chr.ligatures = { } end
+ chr.ligatures[plus] = becomes
end
end
+ if str ~= "" then
+ characters[str] = chr
+ end
+end
- local function get_kernpairs(data,kernpairs)
- local characters = data.characters
- for one, two, value in kernpairs:gmatch("KPX +(.-) +(.-) +(.-)\n") do
- local chr = characters[one]
- if chr then
- if not chr.kerns then chr.kerns = { } end
- chr.kerns[two] = tonumber(value)
- end
+local function get_kernpairs(data,kernpairs)
+ local characters = data.characters
+ for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
+ local chr = characters[one]
+ if chr then
+ if not chr.kerns then chr.kerns = { } end
+ chr.kerns[two] = tonumber(value)
end
end
+end
- local function get_variables(data,fontmetrics)
- for key, rest in fontmetrics:gmatch("(%a+) *(.-)[\n\r]") do
- if keys[key] then keys[key](data,rest) end
- end
+local function get_variables(data,fontmetrics)
+ for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
+ if keys[key] then keys[key](data,rest) end
end
+end
- local function get_indexes(data,filename)
- local trace = fonts.trace
- local pfbname = input.find_file(texmf.instance,file.removesuffix(file.basename(filename))..".pfb","pfb") or ""
- if pfbname ~= "" then
- data.luatex = data.luatex or { }
- data.luatex.filename = pfbname
- local pfbblob = fontforge.open(pfbname)
- if pfbblob then
- local characters = data.characters
- local pfbdata = fontforge.to_table(pfbblob)
- --~ print(table.serialize(pfbdata))
- if pfbdata then
- local glyphs = pfbdata.glyphs
- if glyphs then
- if trace then
- logs.report("load afm", string.format("getting index data from %s",pfbname))
- end
- -- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0
- for index, glyph in pairs(glyphs) do
- local name = glyph.name
- if name then
- local char = characters[name]
- if char then
- if trace then
- logs.report("load afm", string.format("glyph %s has index %s",name,index))
- end
- char.index = index
+local function get_indexes(data,filename)
+ local pfbfile = file.replacesuffix(filename,"pfb")
+ local pfbname = resolvers.find_file(pfbfile,"pfb") or ""
+ if pfbname == "" then
+ pfbname = resolvers.find_file(file.basename(pfbfile),"pfb") or ""
+ end
+ if pfbname ~= "" then
+ data.luatex.filename = pfbname
+ local pfbblob = fontloader.open(pfbname)
+ if pfbblob then
+ local characters = data.characters
+ local pfbdata = fontloader.to_table(pfbblob)
+ --~ print(table.serialize(pfbdata))
+ if pfbdata then
+ local glyphs = pfbdata.glyphs
+ if glyphs then
+ if trace_loading then
+ logs.report("load afm","getting index data from %s",pfbname)
+ end
+ -- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0
+ for index, glyph in next, glyphs do
+ local name = glyph.name
+ if name then
+ local char = characters[name]
+ if char then
+ if trace_indexing then
+ logs.report("load afm","glyph %s has index %s",name,index)
end
+ char.index = index
end
end
- elseif trace then
- logs.report("load afm", string.format("no glyph data in pfb file %s",pfbname))
end
- elseif trace then
- logs.report("load afm", string.format("no data in pfb file %s",pfbname))
+ elseif trace_loading then
+ logs.report("load afm","no glyph data in pfb file %s",pfbname)
end
- elseif trace then
- logs.report("load afm", string.format("invalid pfb file %s",pfbname))
+ elseif trace_loading then
+ logs.report("load afm","no data in pfb file %s",pfbname)
end
- elseif trace then
- logs.report("load afm", string.format("no pfb file for %s",filename))
+ fontloader.close(pfbblob)
+ elseif trace_loading then
+ logs.report("load afm","invalid pfb file %s",pfbname)
end
+ elseif trace_loading then
+ logs.report("load afm","no pfb file for %s",filename)
end
+end
- function fonts.afm.read_afm(filename)
- local ok, afmblob, size = input.loadbinfile(texmf.instance,filename) -- has logging
- -- local ok, afmblob = true, file.readdata(filename)
- if ok and afmblob then
- local data = {
- version = version or '0',
- characters = { },
+function afm.read_afm(filename)
+ local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging
+-- local ok, afmblob = true, file.readdata(filename)
+ if ok and afmblob then
+ local data = {
+ characters = { },
+ metadata = {
+ version = version or '0', -- hm
filename = file.removesuffix(file.basename(filename))
}
- afmblob = afmblob:gsub("StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
- if fonts.trace then
- logs.report("load afm", "loading char metrics")
- end
- get_charmetrics(data,charmetrics,vector)
- return ""
- end)
- afmblob = afmblob:gsub("StartKernPairs(.-)EndKernPairs", function(kernpairs)
- if fonts.trace then
- logs.report("load afm", "loading kern pairs")
- end
- get_kernpairs(data,kernpairs)
- return ""
- end)
- afmblob = afmblob:gsub("StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics)
- if fonts.trace then
- logs.report("load afm", "loading variables")
- end
- data.afmversion = version
- get_variables(data,fontmetrics)
- data.fontdimens = fonts.afm.scan_comment(fontmetrics) -- todo: all lpeg, no time now
- return ""
- end)
- get_indexes(data,filename)
- return data
- else
- if fonts.trace then
- logs.report("load afm", "no valid afm file " .. filename)
+ }
+ afmblob = afmblob:gsub("StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
+ if trace_loading then
+ logs.report("load afm","loading char metrics")
+ end
+ get_charmetrics(data,charmetrics,vector)
+ return ""
+ end)
+ afmblob = afmblob:gsub("StartKernPairs(.-)EndKernPairs", function(kernpairs)
+ if trace_loading then
+ logs.report("load afm","loading kern pairs")
+ end
+ get_kernpairs(data,kernpairs)
+ return ""
+ end)
+ afmblob = afmblob:gsub("StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics)
+ if trace_loading then
+ logs.report("load afm","loading variables")
end
- return nil
+ data.afmversion = version
+ get_variables(data,fontmetrics)
+ data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now
+ return ""
+ end)
+ data.luatex = { }
+ get_indexes(data,filename)
+ return data
+ else
+ if trace_loading then
+ logs.report("load afm","no valid afm file %s",filename)
end
+ return nil
end
-
end
--[[ldx--
@@ -252,56 +259,84 @@ by adding ligatures and kern information to the afm derived data. That
way we can set them faster when defining a font.</p>
--ldx]]--
-function fonts.afm.load(filename)
- local name = file.removesuffix(filename)
- local data = containers.read(fonts.afm.cache(),name)
- local size = lfs.attributes(name,"size") or 0
- if data and data.size ~= size then
- data = nil
- end
- if not data then
- local foundname = input.find_file(texmf.instance,filename,'afm')
- if foundname and foundname ~= "" then
- data = fonts.afm.read_afm(foundname)
+function afm.load(filename)
+ -- hm, for some reasons not resolved yet
+ filename = resolvers.find_file(filename,'afm') or ""
+ if filename ~= "" then
+ local name = file.removesuffix(file.basename(filename))
+ local data = containers.read(afm.cache(),name)
+ local size = lfs.attributes(filename,"size") or 0
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
+ logs.report("load afm", "reading %s",filename)
+ data = afm.read_afm(filename)
if data then
- fonts.afm.unify(data,filename)
- if fonts.afm.enhance_data then
- fonts.afm.add_ligatures(data,'ligatures') -- easier this way
- fonts.afm.add_ligatures(data,'texligatures') -- easier this way
- fonts.afm.add_kerns(data) -- faster this way
+ -- data.luatex = data.luatex or { }
+ logs.report("load afm", "unifying %s",filename)
+ afm.unify(data,filename)
+ if afm.enhance_data then
+ logs.report("load afm", "add ligatures")
+ afm.add_ligatures(data,'ligatures') -- easier this way
+ logs.report("load afm", "add tex-ligatures")
+ afm.add_ligatures(data,'texligatures') -- easier this way
+ logs.report("load afm", "add extra kerns")
+ afm.add_kerns(data) -- faster this way
end
- logs.report("load afm","file size: " .. size)
data.size = size
- logs.report("load afm","saving: in cache")
- data = containers.write(fonts.afm.cache(), name, data)
+ data.verbose = fonts.verbose
+ logs.report("load afm","saving: %s in cache",name)
+ data = containers.write(afm.cache(), name, data)
+ data = containers.read(afm.cache(),name)
end
end
+ return data
+ else
+ return nil
end
- return data
end
-function fonts.afm.unify(data, filename)
---~ local unicode, unicodes, private = fonts.enc.load('unicode').hash, { }, 0x0F0000
- local unicode, unicodes, private = fonts.enc.load('unicode').hash, { }, fonts.private
- for name, blob in pairs(data.characters) do
- local code = unicode[name] -- or characters.name_to_unicode[name]
+function afm.unify(data, filename)
+ local unicodevector = fonts.enc.load('unicode').hash
+ local glyphs, indices, unicodes, names = { }, { }, { }, { }
+ local verbose, private = fonts.verbose, fonts.private
+ for name, blob in next, data.characters do
+ local code = unicodevector[name] -- or characters.name_to_unicode[name]
if not code then
- local u = name:match("^uni(%x+)$")
+ local u = match(name,"^uni(%x+)$")
code = u and tonumber(u,16)
if not code then
code = private
private = private + 1
- logs.report("afm glyph", string.format("assigning private slot 0x%04X for unknown glyph name %s", code, name))
+ logs.report("afm glyph", "assigning private slot U+%04X for unknown glyph name %s", code, name)
end
end
- blob.unicode = code
+ local index = blob.index
unicodes[name] = code
+ indices[code] = index
+ glyphs[index] = blob
+ names[name] = index
+ blob.name = name
+ if verbose then
+ local bu = blob.unicode
+ if not bu then
+ blob.unicode = code
+ elseif type(bu) == "table" then
+ bu[#bu+1] = code
+ else
+ blob.unicode = { bu, code }
+ end
+ else
+ blob.index = nil
+ end
end
- data.luatex = {
- filename = file.basename(filename),
- -- version = fonts.afm.version,
- unicodes = unicodes
- }
+ data.glyphs = glyphs
+ data.characters = nil
+ local luatex = data.luatex
+ luatex.filename = luatex.filename or file.removesuffix(file.basename(filename))
+ luatex.unicodes = unicodes -- name to unicode
+ luatex.indices = indices -- unicode to index
+ luatex.marks = { } -- todo
+ luatex.names = names -- name to index
+ luatex.private = private
end
--[[ldx--
@@ -309,14 +344,15 @@ end
and extra kerns. This saves quite some lookups later.</p>
--ldx]]--
-function fonts.afm.add_ligatures(afmdata,ligatures)
- local chars = afmdata.characters
- for k,v in pairs(characters[ligatures]) do
- local one = chars[k]
+function afm.add_ligatures(afmdata,ligatures)
+ local glyphs, luatex = afmdata.glyphs, afmdata.luatex
+ local indices, unicodes, names = luatex.indices, luatex.unicodes, luatex.names
+ for k,v in next, characters[ligatures] do -- main characters table
+ local one = glyphs[names[k]]
if one then
- for _, b in pairs(v) do
+ for _, b in next, v do
two, three = b[1], b[2]
- if two and three and chars[two] and chars[three] then
+ if two and three and names[two] and names[three] then
local ol = one[ligatures]
if ol then
if not ol[two] then -- was one.ligatures ... bug
@@ -336,39 +372,55 @@ end
them selectively.</p>
--ldx]]--
-function fonts.afm.add_kerns(afmdata)
- local chars = afmdata.characters
- -- add complex with values of simplified when present
+function afm.add_kerns(afmdata)
+ local glyphs = afmdata.glyphs
+ local names = afmdata.luatex.names
+ local uncomposed = characters.uncomposed
local function do_it_left(what)
- for _,v in pairs(chars) do
- if v.kerns then
- local k = { }
- for complex,simple in pairs(characters.uncomposed[what]) do
- local ks = k[simple]
- if ks and not k[complex] then
- k[complex] = ks
+ for index, glyph in next, glyphs do
+ local kerns = glyph.kerns
+ if kerns then
+ local extrakerns = glyph.extrakerns or { }
+ for complex, simple in next, uncomposed[what] do
+ if names[compex] then
+ local ks = kerns[simple]
+ if ks and not kerns[complex] then
+ extrakerns[complex] = ks
+ end
end
end
- if not table.is_empty(k) then
- v.extrakerns = k
+ if next(extrakerns) then
+ glyph.extrakerns = extrakerns
end
end
end
end
- do_it_left("left")
- do_it_left("both")
- -- copy kerns from simple char to complex char unless set
local function do_it_copy(what)
- for complex,simple in pairs(characters.uncomposed[what]) do
- local c = chars[complex]
+ for complex, simple in next, uncomposed[what] do
+ local c = glyphs[names[complex]]
if c then -- optional
- local s = chars[simple]
- if s and s.kerns then
- c.extrakerns = s.kerns -- ok ? no merge ?
+ local s = glyphs[names[simple]]
+ if s then
+ if not c.kerns then
+ c.extrakerns = s.kerns or { }
+ end
+ if s.extrakerns then
+ local extrakerns = c.extrakerns or { }
+ for k, v in next, s.extrakerns do
+ extrakerns[k] = v
+ end
+ if next(extrakerns) then
+ s.extrakerns = extrakerns
+ end
+ end
end
end
end
end
+ -- add complex with values of simplified when present
+ do_it_left("left")
+ do_it_left("both")
+ -- copy kerns from simple char to complex char unless set
do_it_copy("both")
do_it_copy("right")
end
@@ -380,101 +432,137 @@ end
-- once we have otf sorted out (new format) we can try to make the afm
-- cache similar to it (similar tables)
-function fonts.afm.add_dimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name
+function afm.add_dimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name
if data then
- for n, d in pairs(data.characters) do
- local bb = d.boundingbox
+ for index, glyph in next, data.glyphs do
+ local bb = glyph.boundingbox
if bb then
local ht, dp = bb[4], -bb[2]
- if ht ~= 0 then d.height = ht end
- if dp ~= 0 then d.depth = dp end
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ glyph.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
+ else
+ glyph.depth = dp
+ end
end
- d.name = n
end
end
end
-function fonts.afm.copy_to_tfm(data)
- if data and data.characters then
- local tfm = { characters = { }, parameters = { } }
- local afmcharacters = data.characters
- local characters, parameters = tfm.characters, tfm.parameters
- if afmcharacters then
- for k, v in pairs(afmcharacters) do
- characters[v.unicode] = { description = v }
+function afm.copy_to_tfm(data)
+ if data then
+ local glyphs = data.glyphs
+ if glyphs then
+ local metadata, luatex = data.metadata, data.luatex
+ local unicodes, indices = luatex.unicodes, luatex.indices
+ local characters, parameters, descriptions = { }, { }, { }
+ local tfm = {
+ characters = characters,
+ parameters = parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ luatex = luatex,
+ }
+ for u, i in next, indices do
+ local d = glyphs[i]
+ characters[u] = { }
+ descriptions[u] = d
end
- end
- tfm.encodingbytes = data.encodingbytes or 2
- tfm.fullname = data.fullname
- tfm.filename = data.filename
- tfm.name = tfm.fullname -- data.name or tfm.fullname
- tfm.type = "real"
- tfm.units = 1000
- tfm.stretch = stretch
- tfm.slant = slant
- tfm.direction = 0
- tfm.boundarychar_label = 0
- tfm.boundarychar = 65536
- --~ tfm.false_boundarychar = 65536 -- produces invalid tfm in luatex
- tfm.designsize = (data.designsize or 10)*65536
- local spaceunits = 500
- tfm.spacer = "500 units"
- if data.isfixedpitch then
- if afmcharacters['space'] and afmcharacters['space'].width then
- spaceunits, tfm.spacer = afmcharacters['space'].width, "space"
- elseif afmcharacters['emdash'] and afmcharacters['emdash'].width then -- funny default
- spaceunits, tfm.spacer = afmcharacters['emdash'].width, "emdash"
- elseif data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth"
+ tfm.encodingbytes = metadata.encodingbytes or 2
+ tfm.fullname = metadata.fullname
+ tfm.filename = metadata.filename
+ tfm.name = tfm.fullname
+ tfm.psname = tfm.fullname
+ tfm.type = "real"
+ tfm.units = 1000
+ tfm.stretch = stretch -- nil
+ tfm.slant = slant -- nil
+ tfm.direction = 0
+ tfm.boundarychar_label = 0
+ tfm.boundarychar = 65536
+ --~ tfm.false_boundarychar = 65536 -- produces invalid tfm in luatex
+ tfm.designsize = (metadata.designsize or 10)*65536
+ local spaceunits = 500
+ tfm.spacer = "500 units"
+ -- same as otf
+ local endash, emdash = unicodes['space'], unicodes['emdash']
+ if metadata.isfixedpitch then
+ if descriptions[endash] then
+ spaceunits, tfm.spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+ end
+ else
+ if descriptions[endash] then
+ spaceunits, tfm.spacer = descriptions[endash].width, "space"
+ end
+ -- if not spaceunits and descriptions[emdash] then
+ -- spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
+ -- end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+ end
end
- elseif afmcharacters['space'] and afmcharacters['space'].width then
- spaceunits, tfm.spacer = afmcharacters['space'].width, "space"
- elseif data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth variable"
- end
- spaceunits = tonumber(spaceunits)
- parameters.slant = 0
- parameters.space = spaceunits
- parameters.space_stretch = 500
- parameters.space_shrink = 333
- parameters.x_height = 400
- parameters.quad = 1000
- parameters.extra_space = 0
- if spaceunits < 200 then
- -- todo: warning
- end
- tfm.italicangle = data.italicangle
- tfm.ascender = math.abs(data.ascender or 0)
- tfm.descender = math.abs(data.descender or 0)
- if data.italicangle then
- parameters.slant = parameters.slant - math.round(math.tan(data.italicangle*math.pi/180))
- end
- if data.isfixedpitch then
- parameters.space_stretch = 0
- parameters.space_shrink = 0
- elseif fonts.afm.syncspace then
- parameters.space_stretch = spaceunits/2
- parameters.space_shrink = spaceunits/3
- end
- if data.xheight and data.xheight > 0 then
- parameters.x_height = data.xheight
- elseif afmcharacters['x'] and afmcharacters['x'].height then
- parameters.x_height = afmcharacters['x'].height or 0
- end
- local fd = data.fontdimens
- if fd and fd[8] and fd[9] and fd[10] then -- math
- for k,v in pairs(fd) do
- parameters[k] = v
+ --
+ spaceunits = tonumber(spaceunits)
+ parameters.slant = 0
+ parameters.space = spaceunits
+ parameters.space_stretch = 500
+ parameters.space_shrink = 333
+ parameters.x_height = 400
+ parameters.quad = 1000
+ if spaceunits < 200 then
+ -- todo: warning
+ end
+ tfm.ascender = math.abs(metadata.ascender or 0)
+ tfm.descender = math.abs(metadata.descender or 0)
+ local italicangle = data.metadata.italicangle
+ if italicangle then
+ tfm.italicangle = italicangle
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ end
+ if metadata.isfixedpitch then
+ parameters.space_stretch = 0
+ parameters.space_shrink = 0
+ elseif afm.syncspace then
+ parameters.space_stretch = spaceunits/2
+ parameters.space_shrink = spaceunits/3
+ end
+ parameters.extra_space = parameters.space_shrink
+ if metadata.xheight and metadata.xheight > 0 then
+ parameters.x_height = metadata.xheight
+ else
+ -- same as otf
+ local x = unicodes['x']
+ if x then
+ local x = descriptions[x]
+ if x then
+ parameters.x_height = x.height
+ end
+ end
+ --
+ end
+ local fd = data.fontdimens
+ if fd and fd[8] and fd[9] and fd[10] then -- math
+ for k,v in next, fd do
+ parameters[k] = v
+ end
+ end
+ if next(characters) then
+ return tfm
end
end
- if table.is_empty(characters) then
- return nil
- else
- return tfm
- end
- else
- return nil
end
+ return nil
end
--[[ldx--
@@ -484,86 +572,90 @@ to treat this fontformat like any other and handle features in a
more configurable way.</p>
--ldx]]--
-function fonts.afm.features.register(name,default)
- fonts.afm.features.list[#fonts.afm.features.list+1] = name
- fonts.afm.features.default[name] = default
+function afm.features.register(name,default)
+ afm.features.list[#afm.features.list+1] = name
+ afm.features.default[name] = default
end
-function fonts.afm.set_features(tfmdata)
+function afm.set_features(tfmdata)
local shared = tfmdata.shared
local afmdata = shared.afmdata
- -- elsewhere: shared.features = fonts.define.check(shared.features,fonts.afm.features.default)
local features = shared.features
---~ texio.write_nl(table.serialize(features))
if not table.is_empty(features) then
local mode = tfmdata.mode or fonts.mode
- local fi = fonts.initializers[mode]
- if fi and fi.afm then
- local function initialize(list) -- using tex lig and kerning
+ local initializers = fonts.initializers
+ local fi = initializers[mode]
+ local fiafm = fi and fi.afm
+ if fiafm then
+ local lists = {
+ fonts.triggers,
+ afm.features.list,
+ fonts.manipulators,
+ }
+ for l=1,3 do
+ local list = lists[l]
if list then
- for _, f in ipairs(list) do
+ for i=1,#list do
+ local f = list[i]
local value = features[f]
- if value and fi.afm[f] then -- brr
- if fonts.afm.trace_features then
- logs.report("define afm",string.format("initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown'))
+ if value and fiafm[f] then -- brr
+ if trace_features then
+ logs.report("define afm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
end
- fi.afm[f](tfmdata,value)
+ fiafm[f](tfmdata,value)
mode = tfmdata.mode or fonts.mode
- fi = fonts.initializers[mode]
+ fiafm = initializers[mode].afm
end
end
end
end
- initialize(fonts.triggers)
- initialize(fonts.afm.features.list)
- initialize(fonts.manipulators)
end
local fm = fonts.methods[mode]
- if fm and fm.afm then
- local function register(list) -- node manipulations
+ local fmafm = fm and fm.afm
+ if fmfm then
+ local lists = {
+ afm.features.list,
+ }
+ local sp = shared.processors
+ for l=1,1 do
+ local list = lists[l]
if list then
- for _, f in ipairs(list) do
- if features[f] and fm.afm[f] then -- brr
- if not shared.processors then -- maybe also predefine
- shared.processors = { fm.afm[f] }
+ for i=1,#list do
+ local f = list[i]
+ if features[f] and fmafm[f] then -- brr
+ if not sp then
+ sp = { fmafm[f] }
+ shared.processors = sp
else
- shared.processors[#shared.processors+1] = fm.afm[f]
+ sp[#sp+1] = fmafm[f]
end
end
end
end
end
- register(fonts.afm.features.list)
end
end
end
-function fonts.afm.check_features(specification)
- local features, done = fonts.define.check(specification.features.normal,fonts.afm.features.default)
+function afm.check_features(specification)
+ local features, done = fonts.define.check(specification.features.normal,afm.features.default)
if done then
specification.features.normal = features
- fonts.tfm.hash_instance(specification,true)
+ tfm.hash_instance(specification,true)
end
end
-function fonts.afm.afm_to_tfm(specification)
+function afm.afm_to_tfm(specification)
local afmname = specification.filename or specification.name
- local encoding, filename = afmname:match("^(.-)%-(.*)$") -- context: encoding-name.*
- if encoding and filename and fonts.enc.known[encoding] then
- fonts.tfm.set_normal_feature(specification,'encoding',encoding) -- will go away
- if fonts.trace then
- logs.report("load afm", string.format("stripping encoding prefix from filename %s",afmname))
- end
- afmname = filename
- elseif specification.forced == "afm" then
- if fonts.trace then
- logs.report("load afm", string.format("forcing afm format for %s",afmname))
+ if specification.forced == "afm" or specification.format == "afm" then -- move this one up
+ if trace_loading then
+ logs.report("load afm","forcing afm format for %s",afmname)
end
else
- local tfmname = input.findbinfile(texmf.instance,afmname,"ofm") or ""
+ local tfmname = resolvers.findbinfile(afmname,"ofm") or ""
if tfmname ~= "" then
- if fonts.trace then
- logs.report("load afm", string.format("fallback from afm to tfm for %s",afmname))
+ if trace_loading then
+ logs.report("load afm","fallback from afm to tfm for %s",afmname)
end
afmname = ""
end
@@ -571,27 +663,27 @@ function fonts.afm.afm_to_tfm(specification)
if afmname == "" then
return nil
else
- fonts.afm.check_features(specification)
+ afm.check_features(specification)
specification = fonts.define.resolve(specification) -- new, was forgotten
local features = specification.features.normal
local cache_id = specification.hash
- local tfmdata = containers.read(fonts.tfm.cache(), cache_id) -- cache with features applied
+ local tfmdata = containers.read(tfm.cache(), cache_id) -- cache with features applied
if not tfmdata then
- local afmdata = fonts.afm.load(afmname)
+ local afmdata = afm.load(afmname)
if not table.is_empty(afmdata) then
- fonts.afm.add_dimensions(afmdata)
- tfmdata = fonts.afm.copy_to_tfm(afmdata)
+ afm.add_dimensions(afmdata)
+ tfmdata = afm.copy_to_tfm(afmdata)
if not table.is_empty(tfmdata) then
tfmdata.shared = tfmdata.shared or { }
tfmdata.unique = tfmdata.unique or { }
tfmdata.shared.afmdata = afmdata
tfmdata.shared.features = features
- fonts.afm.set_features(tfmdata)
+ afm.set_features(tfmdata)
end
- elseif fonts.trace then
- logs.report("load afm", string.format("no (valid) afm file found with name %s",afmname))
+ elseif trace_loading then
+ logs.report("load afm","no (valid) afm file found with name %s",afmname)
end
- tfmdata = containers.write(fonts.tfm.cache(),cache_id,tfmdata)
+ tfmdata = containers.write(tfm.cache(),cache_id,tfmdata)
end
return tfmdata
end
@@ -605,9 +697,9 @@ those cases, but now that we can handle <l n='opentype'/> directly we no longer
need this features.</p>
--ldx]]--
-fonts.tfm.default_encoding = 'unicode'
+tfm.default_encoding = 'unicode'
-function fonts.tfm.set_normal_feature(specification,name,value)
+function tfm.set_normal_feature(specification,name,value)
if specification and name then
specification.features = specification.features or { }
specification.features.normal = specification.features.normal or { }
@@ -615,15 +707,11 @@ function fonts.tfm.set_normal_feature(specification,name,value)
end
end
-function fonts.tfm.read_from_afm(specification)
---~ local fullname = input.findbinfile(texmf.instance,specification.name,"afm") or ""
---~ if fullname ~= "" then
---~ specification.filename = fullname
---~ end
- local tfmtable = fonts.afm.afm_to_tfm(specification)
+function tfm.read_from_afm(specification)
+ local tfmtable = afm.afm_to_tfm(specification)
if tfmtable then
tfmtable.name = specification.name
- tfmtable = fonts.tfm.scale(tfmtable, specification.size)
+ tfmtable = tfm.scale(tfmtable, specification.size)
local afmdata = tfmtable.shared.afmdata
local filename = afmdata and afmdata.luatex and afmdata.luatex.filename
if not filename then
@@ -631,8 +719,8 @@ function fonts.tfm.read_from_afm(specification)
end
if filename then
tfmtable.encodingbytes = 2
- tfmtable.filename = input.findbinfile(texmf.instance,filename,"") or filename
- tfmtable.fullname = afmdata.fontname or afmdata.fullname
+ tfmtable.filename = resolvers.findbinfile(filename,"") or filename
+ tfmtable.fullname = afmdata.metadata.fontname or afmdata.metadata.fullname
tfmtable.format = 'type1'
tfmtable.name = afmdata.luatex.filename or tfmtable.fullname
end
@@ -649,39 +737,56 @@ end
those that make sense for this format.</p>
--ldx]]--
-function fonts.afm.features.prepare_ligatures(tfmdata,ligatures,value) -- probably faulty / check index
+function afm.features.prepare_ligatures(tfmdata,ligatures,value)
if value then
- local charlist = tfmdata.shared.afmdata.characters
- for k,v in pairs(tfmdata.characters) do
- local ac = charlist[v.name]
- if ac then
- local al = ac[ligatures]
- if al then
- local ligatures = { }
- for k,v in pairs(al) do
- ligatures[charlist[k].unicode] = {
- char = charlist[v].unicode,
+ local afmdata = tfmdata.shared.afmdata
+ local luatex = afmdata.luatex
+ local unicodes = luatex.unicodes
+ local descriptions = tfmdata.descriptions
+ for u, chr in next, tfmdata.characters do
+ local d = descriptions[u]
+ local l = d[ligatures]
+ if l then
+ local ligatures = chr.ligatures
+ if not ligatures then
+ ligatures = { }
+ chr.ligatures = ligatures
+ end
+ for k, v in next, l do
+ local uk, uv = unicodes[k], unicodes[v]
+ if uk and uv then
+ ligatures[uk] = {
+ char = uv,
type = 0
}
end
- v.ligatures = ligatures
end
end
end
end
end
-function fonts.afm.features.prepare_kerns(tfmdata,kerns,value)
+function afm.features.prepare_kerns(tfmdata,kerns,value)
if value then
- local charlist = tfmdata.shared.afmdata.characters
- for _, chr in pairs(tfmdata.characters) do
- local newkerns = charlist[chr.description.name][kerns]
+ local afmdata = tfmdata.shared.afmdata
+ local luatex = afmdata.luatex
+ local unicodes = luatex.unicodes
+ local descriptions = tfmdata.descriptions
+ for u, chr in next, tfmdata.characters do
+ local d = descriptions[u]
+ local newkerns = d[kerns]
if newkerns then
- local t = chr.kerns or { }
- for k,v in pairs(newkerns) do
- t[charlist[k].unicode] = v
+ local kerns = chr.kerns
+ if not kerns then
+ kerns = { }
+ chr.kerns = kerns
+ end
+ for k,v in next, newkerns do
+ local uk = unicodes[k]
+ if uk then
+ kerns[uk] = v
+ end
end
- chr.kerns = t
end
end
end
@@ -689,14 +794,14 @@ end
-- hm, register?
-function fonts.initializers.base.afm.ligatures (tfmdata,value) fonts.afm.features.prepare_ligatures(tfmdata,'ligatures', value) end
-function fonts.initializers.base.afm.texligatures(tfmdata,value) fonts.afm.features.prepare_ligatures(tfmdata,'texligatures',value) end
-function fonts.initializers.base.afm.kerns (tfmdata,value) fonts.afm.features.prepare_kerns (tfmdata,'kerns', value) end
-function fonts.initializers.base.afm.extrakerns (tfmdata,value) fonts.afm.features.prepare_kerns (tfmdata,'extrakerns', value) end
+function fonts.initializers.base.afm.ligatures (tfmdata,value) afm.features.prepare_ligatures(tfmdata,'ligatures', value) end
+function fonts.initializers.base.afm.texligatures(tfmdata,value) afm.features.prepare_ligatures(tfmdata,'texligatures',value) end
+function fonts.initializers.base.afm.kerns (tfmdata,value) afm.features.prepare_kerns (tfmdata,'kerns', value) end
+function fonts.initializers.base.afm.extrakerns (tfmdata,value) afm.features.prepare_kerns (tfmdata,'extrakerns', value) end
-fonts.afm.features.register('liga',true)
-fonts.afm.features.register('kerns',true)
-fonts.afm.features.register('extrakerns') -- needed?
+afm.features.register('liga',true)
+afm.features.register('kerns',true)
+afm.features.register('extrakerns') -- needed?
fonts.initializers.node.afm.ligatures = fonts.initializers.base.afm.ligatures
fonts.initializers.node.afm.texligatures = fonts.initializers.base.afm.texligatures
@@ -708,11 +813,11 @@ fonts.initializers.node.afm.liga = fonts.initializers.base.afm.ligatures
fonts.initializers.base.afm.tlig = fonts.initializers.base.afm.texligatures
fonts.initializers.node.afm.tlig = fonts.initializers.base.afm.texligatures
-fonts.initializers.base.afm.trep = fonts.tfm.replacements
-fonts.initializers.node.afm.trep = fonts.tfm.replacements
+fonts.initializers.base.afm.trep = tfm.replacements
+fonts.initializers.node.afm.trep = tfm.replacements
-fonts.afm.features.register('tlig',true) -- todo: also proper features for afm
-fonts.afm.features.register('trep',true) -- todo: also proper features for afm
+afm.features.register('tlig',true) -- todo: also proper features for afm
+afm.features.register('trep',true) -- todo: also proper features for afm
-- tfm features
@@ -728,7 +833,7 @@ fonts.initializers.node.afm.compose = fonts.initializers.common.compose
-- afm specific, encodings ...kind of obsolete
-fonts.afm.features.register('encoding')
+afm.features.register('encoding')
fonts.initializers.base.afm.encoding = fonts.initializers.common.encoding
fonts.initializers.node.afm.encoding = fonts.initializers.common.encoding
@@ -739,7 +844,7 @@ fonts.initializers.base.afm.onum = fonts.initializers.common.oldstyle
fonts.initializers.base.afm.smcp = fonts.initializers.common.smallcaps
fonts.initializers.base.afm.fkcp = fonts.initializers.common.fakecaps
-fonts.afm.features.register('onum',false)
-fonts.afm.features.register('smcp',false)
-fonts.afm.features.register('fkcp',false)
+afm.features.register('onum',false)
+afm.features.register('smcp',false)
+afm.features.register('fkcp',false)