summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fontloader/misc/fontloader-font-con.lua141
-rw-r--r--src/fontloader/misc/fontloader-font-def.lua5
-rw-r--r--src/fontloader/misc/fontloader-font-dsp.lua66
-rw-r--r--src/fontloader/misc/fontloader-font-map.lua12
-rw-r--r--src/fontloader/misc/fontloader-font-ocl.lua113
-rw-r--r--src/fontloader/misc/fontloader-font-one.lua20
-rw-r--r--src/fontloader/misc/fontloader-font-onr.lua59
-rw-r--r--src/fontloader/misc/fontloader-font-oti.lua2
-rw-r--r--src/fontloader/misc/fontloader-font-otj.lua73
-rw-r--r--src/fontloader/misc/fontloader-font-otl.lua15
-rw-r--r--src/fontloader/misc/fontloader-font-oto.lua10
-rw-r--r--src/fontloader/misc/fontloader-font-ots.lua137
-rw-r--r--src/fontloader/misc/fontloader-font-oup.lua2
-rw-r--r--src/fontloader/misc/fontloader-font-tfm.lua572
-rw-r--r--src/fontloader/misc/fontloader-fonts-demo-vf-1.lua8
-rw-r--r--src/fontloader/misc/fontloader-fonts-enc.lua59
-rw-r--r--src/fontloader/misc/fontloader-fonts.lua5
-rw-r--r--src/fontloader/misc/fontloader-l-table.lua16
-rw-r--r--src/fontloader/misc/fontloader-mplib.lua22
-rw-r--r--src/fontloader/misc/fontloader-plain-tfm.lua120
-rw-r--r--src/fontloader/misc/fontloader-plain.tex8
-rw-r--r--src/fontloader/misc/fontloader-test.tex12
-rw-r--r--src/fontloader/misc/fontloader-util-fil.lua23
-rw-r--r--src/fontloader/misc/fontloader-util-str.lua6
-rw-r--r--src/fontloader/runtime/fontloader-basics-gen.lua1
-rw-r--r--src/fontloader/runtime/fontloader-reference.lua1228
-rw-r--r--src/luaotfload-features.lua126
-rw-r--r--src/luaotfload-init.lua4
-rw-r--r--src/luaotfload-loaders.lua3
-rwxr-xr-xsrc/luaotfload-tool.lua6
30 files changed, 2109 insertions, 765 deletions
diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua
index 1a0daff..9a6f3f8 100644
--- a/src/fontloader/misc/fontloader-font-con.lua
+++ b/src/fontloader/misc/fontloader-font-con.lua
@@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['font-con'] = {
-- some names of table entries will be changed (no _)
local next, tostring, rawget = next, tostring, rawget
-local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub
+local format, match, lower, gsub, find = string.format, string.match, string.lower, string.gsub, string.find
local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
local derivetable = table.derive
@@ -46,102 +46,6 @@ constructors.privateoffset = 0xF0000 -- 0x10FFFF
constructors.cacheintex = true -- so we see the original table in fonts.font
--- Some experimental helpers (handy for tracing):
---
--- todo: extra:
---
--- extra_space => space.extra
--- space => space.width
--- space_stretch => space.stretch
--- space_shrink => space.shrink
-
--- We do keep the x-height, extra_space, space_shrink and space_stretch
--- around as these are low level official names.
-
-constructors.keys = {
- properties = {
- encodingbytes = "number",
- embedding = "number",
- cidinfo = { },
- format = "string",
- fontname = "string",
- fullname = "string",
- filename = "filename",
- psname = "string",
- name = "string",
- virtualized = "boolean",
- hasitalics = "boolean",
- autoitalicamount = "basepoints",
- nostackmath = "boolean",
- noglyphnames = "boolean",
- mode = "string",
- hasmath = "boolean",
- mathitalics = "boolean",
- textitalics = "boolean",
- finalized = "boolean",
- },
- parameters = {
- mathsize = "number",
- scriptpercentage = "float",
- scriptscriptpercentage = "float",
- units = "cardinal",
- designsize = "scaledpoints",
- expansion = {
- stretch = "integerscale", -- might become float
- shrink = "integerscale", -- might become float
- step = "integerscale", -- might become float
- auto = "boolean",
- },
- protrusion = {
- auto = "boolean",
- },
- slantfactor = "float",
- extendfactor = "float",
- factor = "float",
- hfactor = "float",
- vfactor = "float",
- size = "scaledpoints",
- units = "scaledpoints",
- scaledpoints = "scaledpoints",
- slantperpoint = "scaledpoints",
- spacing = {
- width = "scaledpoints",
- stretch = "scaledpoints",
- shrink = "scaledpoints",
- extra = "scaledpoints",
- },
- xheight = "scaledpoints",
- quad = "scaledpoints",
- ascender = "scaledpoints",
- descender = "scaledpoints",
- synonyms = {
- space = "spacing.width",
- spacestretch = "spacing.stretch",
- spaceshrink = "spacing.shrink",
- extraspace = "spacing.extra",
- x_height = "xheight",
- space_stretch = "spacing.stretch",
- space_shrink = "spacing.shrink",
- extra_space = "spacing.extra",
- em = "quad",
- ex = "xheight",
- slant = "slantperpoint",
- },
- },
- description = {
- width = "basepoints",
- height = "basepoints",
- depth = "basepoints",
- boundingbox = { },
- },
- character = {
- width = "scaledpoints",
- height = "scaledpoints",
- depth = "scaledpoints",
- italic = "scaledpoints",
- },
-}
-
-- This might become an interface:
local designsizes = allocate()
@@ -351,6 +255,27 @@ local function mathkerns(v,vdelta)
return k
end
+local psfake = 0
+
+local function fixedpsname(psname,fallback)
+ local usedname = psname
+ if psname and psname ~= "" then
+ if find(psname," ") then
+ usedname = gsub(psname,"[%s]+","-")
+ else
+ -- we assume that the name is sane enough (we might sanitize completely some day)
+ end
+ elseif not fallback or fallback == "" then
+ psfake = psfake + 1
+ psname = "fakename-" .. psfake
+ else
+ -- filenames can be a mess so we do a drastic cleanup
+ psname = fallback
+ usedname = gsub(psname,"[^a-zA-Z0-9]+","-")
+ end
+ return usedname, psname ~= usedname
+end
+
function constructors.scale(tfmdata,specification)
local target = { } -- the new table
--
@@ -453,23 +378,22 @@ function constructors.scale(tfmdata,specification)
target.format = properties.format
target.cache = constructors.cacheintex and "yes" or "renew"
--
- local fontname = properties.fontname or tfmdata.fontname -- for the moment we fall back on
- local fullname = properties.fullname or tfmdata.fullname -- names in the tfmdata although
- local filename = properties.filename or tfmdata.filename -- that is not the right place to
- local psname = properties.psname or tfmdata.psname -- pass them
+ local fontname = properties.fontname or tfmdata.fontname
+ local fullname = properties.fullname or tfmdata.fullname
+ local filename = properties.filename or tfmdata.filename
+ local psname = properties.psname or tfmdata.psname
local name = properties.name or tfmdata.name
--
- if not psname or psname == "" then
- -- name used in pdf file as well as for selecting subfont in ttc/dfont
- psname = fontname or (fullname and fonts.names.cleanname(fullname))
- end
+ -- the psname used in pdf file as well as for selecting subfont in ttc
+ --
+ local psname, psfixed = fixedpsname(psname,fontname or fullname or file.nameonly(filename))
+ --
target.fontname = fontname
target.fullname = fullname
target.filename = filename
target.psname = psname
target.name = name
--
- --
properties.fontname = fontname
properties.fullname = fullname
properties.filename = filename
@@ -602,8 +526,9 @@ function constructors.scale(tfmdata,specification)
-- end of context specific trickery
--
if trace_defining then
- report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a",
- name,fullname,filename,hdelta,vdelta,hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
+ report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a",
+ name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta,
+ hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
end
--
constructors.beforecopyingcharacters(target,tfmdata)
diff --git a/src/fontloader/misc/fontloader-font-def.lua b/src/fontloader/misc/fontloader-font-def.lua
index add42ee..88d6145 100644
--- a/src/fontloader/misc/fontloader-font-def.lua
+++ b/src/fontloader/misc/fontloader-font-def.lua
@@ -8,10 +8,11 @@ if not modules then modules = { } end modules ['font-def'] = {
-- We can overload some of the definers.functions so we don't local them.
-local format, gmatch, match, find, lower, gsub = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub
+local lower, gsub = string.lower, string.gsub
local tostring, next = tostring, next
local lpegmatch = lpeg.match
local suffixonly, removesuffix = file.suffix, file.removesuffix
+local formatters = string.formatters
local allocate = utilities.storage.allocate
@@ -264,7 +265,7 @@ function definers.applypostprocessors(tfmdata)
if type(extrahash) == "string" and extrahash ~= "" then
-- e.g. a reencoding needs this
extrahash = gsub(lower(extrahash),"[^a-z]","-")
- properties.fullname = format("%s-%s",properties.fullname,extrahash)
+ properties.fullname = formatters["%s-%s"](properties.fullname,extrahash)
end
end
end
diff --git a/src/fontloader/misc/fontloader-font-dsp.lua b/src/fontloader/misc/fontloader-font-dsp.lua
index 1e8b3bd..49d5929 100644
--- a/src/fontloader/misc/fontloader-font-dsp.lua
+++ b/src/fontloader/misc/fontloader-font-dsp.lua
@@ -224,10 +224,15 @@ local function readcoverage(f,offset,simple)
return coverage
end
-local function readclassdef(f,offset)
+local function readclassdef(f,offset,preset)
setposition(f,offset)
local classdefformat = readushort(f)
local classdef = { }
+ if type(preset) == "number" then
+ for k=0,preset-1 do
+ classdef[k] = 1
+ end
+ end
if classdefformat == 1 then
local index = readushort(f)
local nofclassdef = readushort(f)
@@ -249,6 +254,13 @@ local function readclassdef(f,offset)
else
report("unknown classdef format %a ",classdefformat)
end
+ if type(preset) == "table" then
+ for k in next, preset do
+ if not classdef[k] then
+ classdef[k] = 1
+ end
+ end
+ end
return classdef
end
@@ -365,7 +377,9 @@ end
-- We generalize the chained lookups so that we can do with only one handler
-- when processing them.
-local function readlookuparray(f,noflookups)
+-- pruned
+
+local function readlookuparray(f,noflookups,nofcurrent)
local lookups = { }
if noflookups > 0 then
local length = 0
@@ -381,10 +395,34 @@ local function readlookuparray(f,noflookups)
lookups[index] = false
end
end
+ -- if length > nofcurrent then
+ -- report_issue("more lookups than currently matched characters")
+ -- end
end
return lookups
end
+-- not pruned
+--
+-- local function readlookuparray(f,noflookups,nofcurrent)
+-- local lookups = { }
+-- for i=1,nofcurrent do
+-- lookups[i] = false
+-- end
+-- for i=1,noflookups do
+-- local index = readushort(f) + 1
+-- if index > nofcurrent then
+-- report_issue("more lookups than currently matched characters")
+-- for i=nofcurrent+1,index-1 do
+-- lookups[i] = false
+-- end
+-- nofcurrent = index
+-- end
+-- lookups[index] = readushort(f) + 1
+-- end
+-- return lookups
+-- end
+
local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
@@ -409,7 +447,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
for i=2,nofcurrent do
current[i] = { readushort(f) }
end
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1] = {
current = current,
lookups = lookups
@@ -433,7 +471,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
local rules = { }
if subclasssets then
coverage = readcoverage(f,tableoffset + coverage)
- currentclassdef = readclassdef(f,tableoffset + currentclassdef)
+ currentclassdef = readclassdef(f,tableoffset + currentclassdef,coverage)
local currentclasses = classtocoverage(currentclassdef,fontdata.glyphs)
for class=1,#subclasssets do
local offset = subclasssets[class]
@@ -452,7 +490,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
for i=2,nofcurrent do
current[i] = currentclasses[readushort(f) + 1]
end
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1] = {
current = current,
lookups = lookups
@@ -476,7 +514,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
elseif subtype == 3 then
local current = readarray(f)
local noflookups = readushort(f)
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,#current)
current = readcoveragearray(f,tableoffset,current,true)
return {
format = "coverage",
@@ -536,7 +574,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
end
end
local noflookups = readushort(f)
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1] = {
before = before,
current = current,
@@ -562,9 +600,9 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local rules = { }
if subclasssets then
local coverage = readcoverage(f,tableoffset + coverage)
- local beforeclassdef = readclassdef(f,tableoffset + beforeclassdef)
- local currentclassdef = readclassdef(f,tableoffset + currentclassdef)
- local afterclassdef = readclassdef(f,tableoffset + afterclassdef)
+ local beforeclassdef = readclassdef(f,tableoffset + beforeclassdef,nofglyphs)
+ local currentclassdef = readclassdef(f,tableoffset + currentclassdef,coverage)
+ local afterclassdef = readclassdef(f,tableoffset + afterclassdef,nofglyphs)
local beforeclasses = classtocoverage(beforeclassdef,fontdata.glyphs)
local currentclasses = classtocoverage(currentclassdef,fontdata.glyphs)
local afterclasses = classtocoverage(afterclassdef,fontdata.glyphs)
@@ -604,7 +642,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
end
-- no sequence index here (so why in context as it saves nothing)
local noflookups = readushort(f)
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1] = {
before = before,
current = current,
@@ -632,7 +670,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local current = readarray(f)
local after = readarray(f)
local noflookups = readushort(f)
- local lookups = readlookuparray(f,noflookups)
+ local lookups = readlookuparray(f,noflookups,#current)
before = readcoveragearray(f,tableoffset,before,true)
current = readcoveragearray(f,tableoffset,current,true)
after = readcoveragearray(f,tableoffset,after,true)
@@ -988,8 +1026,8 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local nofclasses2 = readushort(f) -- incl class 0
local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
coverage = readcoverage(f,tableoffset+coverage)
- classdef1 = readclassdef(f,tableoffset+classdef1)
- classdef2 = readclassdef(f,tableoffset+classdef2)
+ classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
+ classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
local usedcoverage = { }
for g1, c1 in next, classdef1 do
if coverage[g1] then
diff --git a/src/fontloader/misc/fontloader-font-map.lua b/src/fontloader/misc/fontloader-font-map.lua
index 6151b37..7f3b0f9 100644
--- a/src/fontloader/misc/fontloader-font-map.lua
+++ b/src/fontloader/misc/fontloader-font-map.lua
@@ -13,8 +13,8 @@ local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, l
local floor = math.floor
local formatters = string.formatters
-local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
-local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_unimapping = v end)
+local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
+local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_mapping = v end)
local report_fonts = logs.reporter("fonts","loading") -- not otf only
@@ -265,6 +265,9 @@ function mappings.addtounicode(data,filename,checklookups)
local resources = data.resources
local unicodes = resources.unicodes
if not unicodes then
+ if trace_mapping then
+ report_fonts("no unicode list, quitting tounicode for %a",filename)
+ end
return
end
local properties = data.properties
@@ -474,11 +477,10 @@ function mappings.addtounicode(data,filename,checklookups)
if trace_mapping and unicoded > 0 then
report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded)
end
-
if trace_mapping then
for unic, glyph in table.sortedhash(descriptions) do
- local name = glyph.name
- local index = glyph.index
+ local name = glyph.name or "-"
+ local index = glyph.index or 0
local unicode = glyph.unicode
if unicode then
if type(unicode) == "table" then
diff --git a/src/fontloader/misc/fontloader-font-ocl.lua b/src/fontloader/misc/fontloader-font-ocl.lua
index b2aba7a..ed1be95 100644
--- a/src/fontloader/misc/fontloader-font-ocl.lua
+++ b/src/fontloader/misc/fontloader-font-ocl.lua
@@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['font-ocl'] = {
-- todo : user list of colors
-local tostring, next = tostring, next
+local tostring, next, format = tostring, next, string.format
local formatters = string.formatters
@@ -166,34 +166,56 @@ do
end
-if context and xml.convert then
+
+do
local report_svg = logs.reporter("fonts","svg conversion")
- local xmlconvert = xml.convert
- local xmlfirst = xml.first
local loaddata = io.loaddata
local savedata = io.savedata
local remove = os.remove
+ if context and xml.convert then
+
+ local xmlconvert = xml.convert
+ local xmlfirst = xml.first
+
+ function otfsvg.filterglyph(entry,index)
+ local svg = xmlconvert(entry.data)
+ local root = svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
+ local data = root and tostring(root)
+ -- report_svg("data for glyph %04X: %s",index,data)
+ return data
+ end
+
+ else
+
+ function otfsvg.filterglyph(entry,index) -- can be overloaded
+ return entry.data
+ end
+
+ end
+
-- function otfsvg.topdf(svgshapes)
- -- local svgfile = "temp-otf-svg-shape.svg"
- -- local pdffile = "temp-otf-svg-shape.pdf"
- -- local command = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
- -- local testrun = false
- -- local pdfshapes = { }
- -- local nofshapes = #svgshapes
+ -- local svgfile = "temp-otf-svg-shape.svg"
+ -- local pdffile = "temp-otf-svg-shape.pdf"
+ -- local command = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
+ -- local testrun = false
+ -- local pdfshapes = { }
+ -- local nofshapes = #svgshapes
+ -- local filterglyph = otfsvg.filterglyph
-- report_svg("processing %i svg containers",nofshapes)
-- statistics.starttiming()
-- for i=1,nofshapes do
-- local entry = svgshapes[i]
- -- for j=entry.first,entry.last do
- -- local svg = xmlconvert(entry.data)
- -- local data = xmlfirst(svg,"/svg[@id='glyph"..j.."']")
+ -- for index=entry.first,entry.last do
+ -- local data = filterglyph(entry,index)
-- savedata(svgfile,tostring(data))
- -- report_svg("processing svg shape of glyph %i in container %i",j,i)
- -- os.execute(command)
- -- pdfshapes[j] = loaddata(pdffile)
+ -- if data and data ~= "" then
+ -- report_svg("processing svg shape of glyph %i in container %i",index,i)
+ -- os.execute(command)
+ -- pdfshapes[index] = loaddata(pdffile)
+ -- end
-- end
-- if testrun and i > testrun then
-- report_svg("quiting test run")
@@ -207,26 +229,25 @@ if context and xml.convert then
-- end
function otfsvg.topdf(svgshapes)
- local inkscape = io.popen("inkscape --shell 2>&1","w")
- local pdfshapes = { }
- local nofshapes = #svgshapes
- local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
- local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert = formatters["%s --export-pdf=%s\n"]
+ local inkscape = io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
+ local pdfshapes = { }
+ local nofshapes = #svgshapes
+ local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert = formatters["%s --export-pdf=%s\n"]
+ local filterglyph = otfsvg.filterglyph
report_svg("processing %i svg containers",nofshapes)
statistics.starttiming()
for i=1,nofshapes do
local entry = svgshapes[i]
- for j=entry.first,entry.last do
- local svg = xmlconvert(entry.data)
- local root = svg and xmlfirst(svg,"/svg[@id='glyph"..j.."']")
- local data = root and tostring(root)
+ for index=entry.first,entry.last do
+ local data = filterglyph(entry,index)
if data and data ~= "" then
- local svgfile = f_svgfile(j)
- local pdffile = f_pdffile(j)
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
savedata(svgfile,data)
inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[j] = true
+ pdfshapes[index] = true
end
end
end
@@ -236,39 +257,17 @@ if context and xml.convert then
-- end
inkscape:close()
report_svg("processing %i pdf results",nofshapes)
- for i in next, pdfshapes do
- local svgfile = f_svgfile(i)
- local pdffile = f_pdffile(i)
- pdfshapes[i] = loaddata(pdffile)
+ for index in next, pdfshapes do
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
+ pdfshapes[index] = loaddata(pdffile)
remove(svgfile)
remove(pdffile)
end
statistics.stoptiming()
- report_svg("conversion time: %0.3f",statistics.elapsedtime())
- return pdfshapes
- end
-
-else
-
- function otfsvg.topdf(svgshapes)
- local svgfile = "temp-otf-svg-shape.svg"
- local pdffile = "temp-otf-svg-shape.pdf"
- local command = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
- local pdfshapes = { }
- local nofshapes = #svgshapes
- texio.write(formatters["[converting %i svg glyphs to pdf using command %q : "](nofshapes,command))
- for i=1,nofshapes do
- local entry = svgshapes[i]
- for j=entry.first,entry.last do
- -- cross our fingers .. some, day i will filter
- texio.write(formatters["%i "](j))
- io.savedata(svgfile,tostring(entry.data))
- os.execute(command)
- pdfshapes[j] = io.loaddata(pdffile)
- end
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds())
end
- os.remove(svgfile)
- texio.write("done]")
return pdfshapes
end
diff --git a/src/fontloader/misc/fontloader-font-one.lua b/src/fontloader/misc/fontloader-font-one.lua
index a6f47e8..8629850 100644
--- a/src/fontloader/misc/fontloader-font-one.lua
+++ b/src/fontloader/misc/fontloader-font-one.lua
@@ -86,7 +86,8 @@ local steps = {
"add ligatures",
"add extra kerns",
"normalize features",
- "fix names",
+ "check extra features",
+ "fix names", -- what a hack ...
-- "add tounicode data",
}
@@ -318,6 +319,8 @@ enhancers["normalize features"] = function(data)
data.resources.sequences = sequences
end
+enhancers["check extra features"] = otf.enhancers.enhance
+
enhancers["fix names"] = function(data)
for k, v in next, data.descriptions do
local n = v.name
@@ -752,18 +755,12 @@ end
<p>We have the usual two modes and related features initializers and processors.</p>
--ldx]]--
-local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode = lower(value)
- end
-end
-
registerafmfeature {
name = "mode",
description = "mode",
initializers = {
- base = setmode,
- node = setmode,
+ base = otf.modeinitializer,
+ node = otf.modeinitializer,
}
}
@@ -782,8 +779,6 @@ registerafmfeature {
-- readers
-local check_tfm = readers.check_tfm
-
fonts.formats.afm = "type1"
fonts.formats.pfb = "type1"
@@ -820,7 +815,8 @@ function readers.afm(specification,method)
tfmdata = check_afm(specification,specification.name .. "." .. forced)
end
if not tfmdata then
- method = method or definers.method or "afm or tfm"
+ local check_tfm = readers.check_tfm
+ method = (check_tfm and (method or definers.method or "afm or tfm")) or "afm"
if method == "tfm" then
tfmdata = check_tfm(specification,specification.name)
elseif method == "afm" then
diff --git a/src/fontloader/misc/fontloader-font-onr.lua b/src/fontloader/misc/fontloader-font-onr.lua
index a4969ad..dcf7445 100644
--- a/src/fontloader/misc/fontloader-font-onr.lua
+++ b/src/fontloader/misc/fontloader-font-onr.lua
@@ -21,23 +21,21 @@ add features.</p>
local fonts, logs, trackers, resolvers = fonts, logs, trackers, resolvers
-local next, type, tonumber, rawget = next, type, tonumber, rawget
+local next, type, tonumber, rawget, rawset = next, type, tonumber, rawget, rawset
local match, lower, gsub, strip, find = string.match, string.lower, string.gsub, string.strip, string.find
local char, byte, sub = string.char, string.byte, string.sub
local abs = math.abs
local bxor, rshift = bit32.bxor, bit32.rshift
-local P, S, R, Cmt, C, Ct, Cs, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg
+local P, S, R, Cmt, C, Ct, Cs, Carg, Cf, Cg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg, lpeg.Cf, lpeg.Cg
local lpegmatch, patterns = lpeg.match, lpeg.patterns
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 report_afm = logs.reporter("fonts","afm loading")
-local report_afm = logs.reporter("fonts","pfb loading")
+local report_pfb = logs.reporter("fonts","pfb loading")
-fonts = fonts or { }
-local handlers = fonts.handlers or { }
-fonts.handlers = handlers
+local handlers = fonts.handlers
local afm = handlers.afm or { }
handlers.afm = afm
local readers = afm.readers or { }
@@ -72,20 +70,36 @@ do
local initialize = function(str,position,size)
n = 0
- m = tonumber(size)
+ m = size -- % tonumber(size)
return position + 1
end
- local charstrings = P("/CharStrings")
- local name = P("/") * C((R("az")+R("AZ")+R("09")+S("-_."))^1)
- local size = C(R("09")^1)
- local spaces = P(" ")^1
+ local charstrings = P("/CharStrings")
+ local encoding = P("/Encoding")
+ local dup = P("dup")
+ local put = P("put")
+ local array = P("array")
+ local name = P("/") * C((R("az")+R("AZ")+R("09")+S("-_."))^1)
+ local digits = R("09")^1
+ local cardinal = digits / tonumber
+ local spaces = P(" ")^1
+ local spacing = patterns.whitespace^0
local p_filternames = Ct (
- (1-charstrings)^0 * charstrings * spaces * Cmt(size,initialize)
- * (Cmt(name * P(" ")^1 * C(R("09")^1), progress) + P(1))^1
+ (1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize)
+ * (Cmt(name * spaces * cardinal, progress) + P(1))^1
)
+ -- /Encoding 256 array
+ -- 0 1 255 {1 index exch /.notdef put} for
+ -- dup 0 /Foo put
+
+ local p_filterencoding =
+ (1-encoding)^0 * encoding * spaces * digits * spaces * array * (1-dup)^0
+ * Cf(
+ Ct("") * Cg(spacing * dup * spaces * cardinal * spaces * name * spaces * put)^1
+ ,rawset)
+
-- if one of first 4 not 0-9A-F then binary else hex
local decrypt
@@ -143,20 +157,31 @@ do
local vector = lpegmatch(p_filternames,binary)
- if vector[1] == ".notdef" then
- -- tricky
- vector[0] = table.remove(vector,1)
+-- if vector[1] == ".notdef" then
+-- -- tricky
+-- vector[0] = table.remove(vector,1)
+-- end
+
+ for i=1,#vector do
+ vector[i-1] = vector[i]
end
+ vector[#vector] = nil
if not vector then
report_pfb("no vector in %a",filename)
return
end
- return vector
+ local encoding = lpegmatch(p_filterencoding,ascii)
+
+ return vector, encoding
end
+ local pfb = handlers.pfb or { }
+ handlers.pfb = pfb
+ pfb.loadvector = loadpfbvector
+
get_indexes = function(data,pfbname)
local vector = loadpfbvector(pfbname)
if vector then
diff --git a/src/fontloader/misc/fontloader-font-oti.lua b/src/fontloader/misc/fontloader-font-oti.lua
index d74d2d5..5e812bb 100644
--- a/src/fontloader/misc/fontloader-font-oti.lua
+++ b/src/fontloader/misc/fontloader-font-oti.lua
@@ -34,6 +34,8 @@ local function setmode(tfmdata,value)
end
end
+otf.modeinitializer = setmode
+
local function setlanguage(tfmdata,value)
if value then
local cleanvalue = lower(value)
diff --git a/src/fontloader/misc/fontloader-font-otj.lua b/src/fontloader/misc/fontloader-font-otj.lua
index d1408fd..46b2ca8 100644
--- a/src/fontloader/misc/fontloader-font-otj.lua
+++ b/src/fontloader/misc/fontloader-font-otj.lua
@@ -36,7 +36,7 @@ local registertracker = trackers.register
local trace_injections = false registertracker("fonts.injections", function(v) trace_injections = v end)
local trace_marks = false registertracker("fonts.injections.marks", function(v) trace_marks = v end)
local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end)
-local trace_spaces = false registertracker("otf.spaces", function(v) trace_spaces = v end)
+local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end)
-- use_advance is just an experiment: it makes copying glyphs (instead of new_glyph) dangerous
@@ -1092,6 +1092,10 @@ local function inject_everything(head,where)
nofmarks = nofmarks + 1
marks[nofmarks] = current
else
+local yoffset = i.yoffset
+if yoffset and yoffset ~= 0 then
+ setfield(current,"yoffset",yoffset)
+end
if hascursives then
local cursivex = i.cursivex
if cursivex then
@@ -1144,10 +1148,10 @@ local function inject_everything(head,where)
end
end
-- left|glyph|right
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(current,"yoffset",yoffset)
- end
+-- local yoffset = i.yoffset
+-- if yoffset and yoffset ~= 0 then
+-- setfield(current,"yoffset",yoffset)
+-- end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
insert_node_before(head,current,newkern(leftkern))
@@ -1422,6 +1426,48 @@ function nodes.injections.setspacekerns(font,sequence)
end
end
+local getthreshold
+
+if context then
+
+ local threshold = 1 -- todo: add a few methods for context
+ local parameters = fonts.hashes.parameters
+
+ directives.register("otf.threshold", function(v) threshold = tonumber(v) or 1 end)
+
+ getthreshold = function(font)
+ local p = parameters[font]
+ local f = p.factor
+ local s = p.spacing
+ local t = threshold * (s and s.width or p.space or 0) - 2
+ return t > 0 and t or 0, f
+ end
+
+else
+
+ injections.threshold = 0
+
+ getthreshold = function(font)
+ local p = fontdata[font].parameters
+ local f = p.factor
+ local s = p.spacing
+ local t = injections.threshold * (s and s.width or p.space or 0) - 2
+ return t > 0 and t or 0, f
+ end
+
+end
+
+injections.getthreshold = getthreshold
+
+function injections.isspace(n,threshold)
+ if getid(n) == glue_code then
+ local w = getfield(n,"width")
+ if threshold and w > threshold then -- was >=
+ return 32
+ end
+ end
+end
+
local function injectspaces(head)
if not triggers then
@@ -1438,18 +1484,11 @@ local function injectspaces(head)
local rightkern = false
local function updatefont(font,trig)
- -- local resources = resources[font]
- -- local spacekerns = resources.spacekerns
- -- if spacekerns then
- -- leftkerns = spacekerns.left
- -- rightkerns = spacekerns.right
- -- end
leftkerns = trig.left
rightkerns = trig.right
- local par = fontdata[font].parameters -- fallback for generic
- factor = par.factor
- threshold = par.spacing.width - 1 -- get rid of rounding errors
lastfont = font
+ threshold,
+ factor = getthreshold(font)
end
for n in traverse_id(glue_code,tonut(head)) do
@@ -1469,7 +1508,7 @@ local function injectspaces(head)
end
end
if prevchar then
- local font = getfont(next)
+ local font = getfont(prev)
local trig = triggers[font]
if trig then
if lastfont ~= font then
@@ -1482,7 +1521,7 @@ local function injectspaces(head)
end
if leftkern then
local old = getfield(n,"width")
- if old >= threshold then
+ if old > threshold then
if rightkern then
local new = old + (leftkern + rightkern) * factor
if trace_spaces then
@@ -1501,7 +1540,7 @@ local function injectspaces(head)
leftkern = false
elseif rightkern then
local old = getfield(n,"width")
- if old >= threshold then
+ if old > threshold then
local new = old + rightkern * factor
if trace_spaces then
report_spaces("[%p -> %p] %C",nextchar,old,new)
diff --git a/src/fontloader/misc/fontloader-font-otl.lua b/src/fontloader/misc/fontloader-font-otl.lua
index 59d868b..a35db5b 100644
--- a/src/fontloader/misc/fontloader-font-otl.lua
+++ b/src/fontloader/misc/fontloader-font-otl.lua
@@ -53,7 +53,7 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.023 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.025 -- beware: also sync font-mis.lua and in mtx-fonts
otf.cache = containers.define("fonts", "otl", otf.version, true)
otf.svgcache = containers.define("fonts", "svg", otf.version, true)
otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
@@ -305,7 +305,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
collectgarbage("collect")
end
stoptiming(otfreaders)
- if elapsedtime then -- not in generic
+ if elapsedtime then
report_otf("loading, optimizing, packing and caching time %s", elapsedtime(otfreaders))
end
if cleanup > 3 then
@@ -340,7 +340,6 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
data.metadata.math = data.resources.mathconstants
end
-
return data
end
@@ -507,14 +506,14 @@ local function copytotfm(data,cache_id)
spaceunits, spacer = charwidth, "charwidth"
end
end
- spaceunits = tonumber(spaceunits) or 500 -- brrr
+ spaceunits = tonumber(spaceunits) or units/2
--
parameters.slant = 0
- parameters.space = spaceunits -- 3.333 (cmr10)
+ parameters.space = spaceunits -- 3.333 (cmr10)
parameters.space_stretch = 1*units/2 -- 500 -- 1.666 (cmr10)
- parameters.space_shrink = 1*units/3 -- 333 -- 1.111 (cmr10)
- parameters.x_height = 2*units/5 -- 400
- parameters.quad = units -- 1000
+ parameters.space_shrink = 1*units/3 -- 333 -- 1.111 (cmr10)
+ parameters.x_height = 2*units/5 -- 400
+ parameters.quad = units -- 1000
if spaceunits < 2*units/5 then
-- todo: warning
end
diff --git a/src/fontloader/misc/fontloader-font-oto.lua b/src/fontloader/misc/fontloader-font-oto.lua
index 1199778..177382f 100644
--- a/src/fontloader/misc/fontloader-font-oto.lua
+++ b/src/fontloader/misc/fontloader-font-oto.lua
@@ -120,7 +120,7 @@ local function registerbasehash(tfmdata)
basehash[hash] = base
end
properties.basehash = base
- properties.fullname = properties.fullname .. "-" .. base
+ properties.fullname = (properties.fullname or properties.name) .. "-" .. base
-- report_prepare("fullname base hash '%a, featureset %a",tfmdata.properties.fullname,hash)
applied = { }
end
@@ -225,6 +225,11 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local trace_alternatives = trace_baseinit and trace_alternatives
local trace_ligatures = trace_baseinit and trace_ligatures
+ if not changed then
+ changed = { }
+ tfmdata.changed = changed
+ end
+
for i=1,#lookuplist do
local sequence = lookuplist[i]
local steps = sequence.steps
@@ -392,7 +397,8 @@ local function featuresinitializer(tfmdata,value)
local properties = tfmdata.properties
local script = properties.script
local language = properties.language
- local rawfeatures = rawdata.resources.features
+ local rawresources = rawdata.resources
+ local rawfeatures = rawresources and rawresources.features
local basesubstitutions = rawfeatures and rawfeatures.gsub
local basepositionings = rawfeatures and rawfeatures.gpos
--
diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua
index d63d524..0f38508 100644
--- a/src/fontloader/misc/fontloader-font-ots.lua
+++ b/src/fontloader/misc/fontloader-font-ots.lua
@@ -134,12 +134,8 @@ local trace_discruns = false registertracker("otf.discruns", function(v
local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end)
-local quit_on_no_replacement = true -- maybe per font
-local zwnjruns = true
-local optimizekerns = true
-
-registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
-registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end)
+----- zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
+local optimizekerns = true
local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
@@ -239,6 +235,7 @@ local cursonce = true
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
+local fontfeatures = fonthashes.features
local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
@@ -269,16 +266,8 @@ local notmatchreplace = { }
local handlers = { }
--- helper
-
-local function isspace(n)
- if getid(n) == glue_code then
- local w = getfield(n,"width")
- if w >= threshold then
- return 32
- end
- end
-end
+local isspace = injections.isspace
+local getthreshold = injections.getthreshold
-- we use this for special testing and documentation
@@ -605,7 +594,7 @@ end
return head, base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks)
+local function multiple_glyphs(head,start,multiple,ignoremarks,what)
local nofmultiples = #multiple
if nofmultiples > 0 then
resetinjection(start)
@@ -613,17 +602,29 @@ local function multiple_glyphs(head,start,multiple,ignoremarks)
if nofmultiples > 1 then
local sn = getnext(start)
for k=2,nofmultiples do
--- untested:
---
--- while ignoremarks and marks[getchar(sn)] then
--- local sn = getnext(sn)
--- end
+ -- untested:
+ --
+ -- while ignoremarks and marks[getchar(sn)] then
+ -- local sn = getnext(sn)
+ -- end
local n = copy_node(start) -- ignore components
resetinjection(n)
setchar(n,multiple[k])
insert_node_after(head,start,n)
start = n
end
+ if what == true then
+ -- we're ok
+ elseif what > 1 then
+ local m = multiple[nofmultiples]
+ for i=2,what do
+ local n = copy_node(start) -- ignore components
+ resetinjection(n)
+ setchar(n,m)
+ insert_node_after(head,start,n)
+ start = n
+ end
+ end
end
return head, start, true
else
@@ -705,7 +706,7 @@ function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1])
+ return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
end
function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
@@ -1237,7 +1238,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup
if trace_multiples then
logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
end
- return multiple_glyphs(head,start,replacement,sequence.flags[1])
+ return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
end
return head, start, false
end
@@ -1262,7 +1263,7 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku
end
local kind = dataset[4]
local what = dataset[1]
- local value = what == true and tfmdata.shared.features[kind] or what
+ local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx
local current = start
while current do
local currentchar = ischar(current)
@@ -2295,16 +2296,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
-- maybe only if match
prev = getprev(prev)
- elseif seq[n][32] then
+ elseif seq[n][32] and isspace(prev,threshold) then
n = n - 1
prev = getprev(prev)
else
match = false
break
end
- elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
- n = n - 1
- prev = getprev(prev) -- was absent
else
match = false
break
@@ -2424,15 +2422,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
-- maybe only if match
current = getnext(current)
- elseif seq[n][32] then -- brrr
+ elseif seq[n][32] and isspace(current,threshold) then
n = n + 1
+ current = getnext(current)
else
match = false
break
end
- elseif seq[n][32] then
- n = n + 1
- current = getnext(current)
else
match = false
break
@@ -2545,7 +2541,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
if replacements then
head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode)
else
- done = quit_on_no_replacement -- can be meant to be skipped / quite inconsistent in fonts
+ done = true
if trace_contexts then
logprocess("%s: skipping match",cref(dataset,sequence))
end
@@ -2728,10 +2724,10 @@ local function kernrun(disc,k_run,font,attr,...)
end
end
--
- if prev and (pre or replace) and not ischar(prev,font) then
+ if prev and not ischar(prev,font) then -- and (pre or replace)
prev = false
end
- if next and (post or replace) and not ischar(next,font) then
+ if next and not ischar(next,font) then -- and (post or replace)
next = false
end
--
@@ -3306,13 +3302,13 @@ local function featuresprocessor(head,font,attr)
if nesting == 1 then
- currentfont = font
- tfmdata = fontdata[font]
- descriptions = tfmdata.descriptions
- characters = tfmdata.characters
- marks = tfmdata.resources.marks
- factor = tfmdata.parameters.factor
- threshold = tfmdata.parameters.spacing.width or 65536*10
+ currentfont = font
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ marks = tfmdata.resources.marks
+ threshold,
+ factor = getthreshold(font)
elseif currentfont ~= font then
@@ -3371,15 +3367,12 @@ local function featuresprocessor(head,font,attr)
local nofsteps = sequence.nofsteps
if not steps then
-- this permits injection, watch the different arguments
- local h, d, ok = handler(head,start,dataset,sequence,nil,nil,nil,0,font,attr)
+ local h, d, ok = handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
if ok then
success = true
if h then
head = h
end
- if d then
- start = d
- end
end
elseif typ == "gsub_reversecontextchain" then
-- this is a limited case, no special treatments like 'init' etc
@@ -3596,12 +3589,29 @@ otf.handlers = handlers -- used in devanagari
local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end
-function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
- -- if not setspacekerns then
- -- setspacekerns = nodes.injections.setspacekerns
- -- end
- setspacekerns(font,sequence)
- return head, start, true
+if fontfeatures then
+
+ function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ local features = fontfeatures[font]
+ local enabled = features.spacekern == true and features.kern == true
+ if enabled then
+ setspacekerns(font,sequence)
+ end
+ return head, start, enabled
+ end
+
+else -- generic (no hashes)
+
+ function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ local shared = fontdata[font].shared
+ local features = shared and shared.features
+ local enabled = features and features.spacekern == true and features.kern == true
+ if enabled then
+ setspacekerns(font,sequence)
+ end
+ return head, start, enabled
+ end
+
end
local function hasspacekerns(data)
@@ -3636,11 +3646,13 @@ otf.readers.registerextender {
end
}
+-- we merge the lookups but we still honor the language / script
+
local function spaceinitializer(tfmdata,value) -- attr
local resources = tfmdata.resources
local spacekerns = resources and resources.spacekerns
- if spacekerns == nil then
- local properties = tfmdata.properties
+ local properties = tfmdata.properties
+ if value and spacekerns == nil then
if properties and properties.hasspacekerns then
local sequences = resources.sequences
local left = { }
@@ -3653,7 +3665,20 @@ local function spaceinitializer(tfmdata,value) -- attr
if steps then
local kern = sequence.features.kern
if kern then
- feat = feat or kern -- or maybe merge
+ if feat then
+ for script, languages in next, kern do
+ local f = feat[k]
+ if f then
+ for l in next, languages do
+ f[l] = true
+ end
+ else
+ feat[script] = languages
+ end
+ end
+ else
+ feat = kern
+ end
for i=1,#steps do
local step = steps[i]
local coverage = step.coverage
diff --git a/src/fontloader/misc/fontloader-font-oup.lua b/src/fontloader/misc/fontloader-font-oup.lua
index 571c69f..c494573 100644
--- a/src/fontloader/misc/fontloader-font-oup.lua
+++ b/src/fontloader/misc/fontloader-font-oup.lua
@@ -848,6 +848,8 @@ function readers.getcomponents(fontdata) -- handy for resolving ligatures when n
end
end
+readers.unifymissing = unifymissing
+
function readers.rehash(fontdata,hashmethod) -- TODO: combine loops in one
if not (fontdata and fontdata.glyphs) then
return
diff --git a/src/fontloader/misc/fontloader-font-tfm.lua b/src/fontloader/misc/fontloader-font-tfm.lua
index ab6d795..d9b0523 100644
--- a/src/fontloader/misc/fontloader-font-tfm.lua
+++ b/src/fontloader/misc/fontloader-font-tfm.lua
@@ -6,8 +6,9 @@ if not modules then modules = { } end modules ['font-tfm'] = {
license = "see context related readme files"
}
-local next = next
-local match = string.match
+local next, type = next, type
+local match, format = string.match, string.format
+local concat, sortedhash = table.concat, table.sortedhash
local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
local trace_features = false trackers.register("tfm.features", function(v) trace_features = v end)
@@ -16,6 +17,7 @@ local report_defining = logs.reporter("fonts","defining")
local report_tfm = logs.reporter("fonts","tfm loading")
local findbinfile = resolvers.findbinfile
+local setmetatableindex = table.setmetatableindex
local fonts = fonts
local handlers = fonts.handlers
@@ -28,8 +30,10 @@ tfm.version = 1.000
tfm.maxnestingdepth = 5
tfm.maxnestingsize = 65536*1024
+local otf = fonts.handlers.otf
+
local tfmfeatures = constructors.features.tfm
------ registertfmfeature = tfmfeatures.register
+local registertfmfeature = tfmfeatures.register
constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua
@@ -69,7 +73,68 @@ function tfm.setfeatures(tfmdata,features)
end
end
-local depth = { } -- table.setmetatableindex("number")
+local depth = { } -- table.setmetatableindex("number")
+local enhancers = { }
+
+local steps = {
+ "normalize features",
+ "check extra features"
+}
+
+-- otf.enhancers.register("check extra features",enhance)
+
+enhancers["check extra features"] = otf.enhancers.enhance
+
+local function applyenhancers(data,filename)
+ for i=1,#steps do
+ local step = steps[i]
+ local enhancer = enhancers[step]
+ if enhancer then
+ if trace_loading then
+ report_tfm("applying enhancer %a",step)
+ end
+ enhancer(data,filename)
+ else
+ report_tfm("invalid enhancer %a",step)
+ end
+ end
+end
+
+-- Normally we just load the tfm data and go on. However there was some demand for
+-- loading good old tfm /pfb files where afm files were lacking and even enc files
+-- of dubious quality so we now support loading such (often messy) setups too.
+--
+-- Because such fonts also use (ugly) tweaks achieve some purpose (like swapping
+-- accents) we need to delay the unicoding actions till after the features have been
+-- applied.
+--
+-- It must be noted that in ConTeXt we don't expect this to be used at all. Here is
+-- example:
+--
+-- tfm metrics + pfb vector for index + pfb file for shapes
+--
+-- \font\foo=file:csr10.tfm:reencode=auto;mode=node;liga=yes;kern=yes
+--
+-- tfm metrics + pfb vector for index + enc file for tfm mapping + pfb file for shapes
+--
+-- \font\foo=file:csr10.tfm:reencode=csr.enc;mode=node;liga=yes;kern=yes
+--
+-- tfm metrics + enc file for mapping to tfm + bitmaps shapes
+--
+-- \font\foo=file:csr10.tfm:reencode=csr.enc;bitmap=yes;mode=node;liga=yes;kern=yes
+--
+-- One can add features:
+--
+-- fonts.handlers.otf.addfeature {
+-- name = "czechdqcheat",
+-- type = "substitution",
+-- data = {
+-- quotedblright = "csquotedblright",
+-- },
+-- }
+--
+-- So "czechdqcheat=yes" is then a valid feature. And yes, it's a cheat.
+
local function read_from_tfm(specification)
local filename = specification.filename
@@ -80,26 +145,116 @@ local function read_from_tfm(specification)
end
local tfmdata = font.read_tfm(filename,size) -- not cached, fast enough
if tfmdata then
- local features = specification.features and specification.features.normal or { }
+
+ local features = specification.features and specification.features.normal or { }
+ local features = constructors.checkedfeatures("tfm",features)
+ specification.features.normal = features
+
+ -- If reencode returns a new table, we assume that we're doing something
+ -- special. An 'auto' reencode pickt up its vector from the pfb file.
+
+ local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification)
+ if newtfmdata then
+ tfmdata = newtfmdata
+ end
+
local resources = tfmdata.resources or { }
local properties = tfmdata.properties or { }
local parameters = tfmdata.parameters or { }
local shared = tfmdata.shared or { }
- properties.name = tfmdata.name
- properties.fontname = tfmdata.fontname
- properties.psname = tfmdata.psname
- properties.filename = specification.filename
- properties.format = fonts.formats.tfm -- better than nothing
- parameters.size = size
+ --
+ shared.features = features
+ shared.resources = resources
+ --
+ properties.name = tfmdata.name -- todo: fallback
+ properties.fontname = tfmdata.fontname -- todo: fallback
+ properties.psname = tfmdata.psname -- todo: fallback
+ properties.fullname = tfmdata.fullname -- todo: fallback
+ properties.filename = specification.filename -- todo: fallback
+ properties.format = fonts.formats.tfm -- better than nothing
--
tfmdata.properties = properties
tfmdata.resources = resources
tfmdata.parameters = parameters
tfmdata.shared = shared
--
- shared.rawdata = { }
+ shared.rawdata = { resources = resources }
shared.features = features
+ --
+ -- The next branch is only entered when we have a proper encoded file i.e.
+ -- unicodes and such. It really nakes no sense to do feature juggling when
+ -- we have no names and unicodes.
+ --
+ if newtfmdata then
+ --
+ -- Some opentype processing assumes these to be present:
+ --
+ if not resources.marks then
+ resources.marks = { }
+ end
+ if not resources.sequences then
+ resources.sequences = { }
+ end
+ if not resources.features then
+ resources.features = {
+ gsub = { },
+ gpos = { },
+ }
+ end
+ if not tfmdata.changed then
+ tfmdata.changed = { }
+ end
+ if not tfmdata.descriptions then
+ tfmdata.descriptions = tfmdata.characters
+ end
+ --
+ -- It might be handy to have this:
+ --
+ otf.readers.addunicodetable(tfmdata)
+ --
+ -- We make a pseudo opentype font, e.g. kerns and ligatures etc:
+ --
+ applyenhancers(tfmdata,filename)
+ --
+ -- Now user stuff can kick in.
+ --
+ constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
+ --
+ -- As that can also mess with names and such, we are now ready for finalizing
+ -- the unicode information. This is a different order that for instance type one
+ -- (afm) files. First we try to deduce unicodes from already present information.
+ --
+ otf.readers.unifymissing(tfmdata)
+ --
+ -- Next we fill in the gaps, based on names from teh agl. Probably not much will
+ -- happen here.
+ --
+ fonts.mappings.addtounicode(tfmdata,filename)
+ --
+ -- The tounicode data is passed to the backend that constructs the vectors for us.
+ --
+ tfmdata.tounicode = 1
+ local tounicode = fonts.mappings.tounicode
+ for unicode, v in next, tfmdata.characters do
+ local u = v.unicode
+ if u then
+ v.tounicode = tounicode(u)
+ end
+ end
+ --
+ -- However, when we use a bitmap font those vectors can't be constructed because
+ -- that information is not carried with those fonts (there is no name info, nor
+ -- proper index info, nor unicodes at that end). So, we provide it ourselves.
+ --
+ if tfmdata.usedbitmap then
+ tfm.addtounicode(tfmdata)
+ end
+ end
+ --
shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil
+ --
+ parameters.factor = 1 -- already scaled
+ parameters.size = size
parameters.slant = parameters.slant or parameters[1] or 0
parameters.space = parameters.space or parameters[2] or 0
parameters.space_stretch = parameters.space_stretch or parameters[3] or 0
@@ -110,7 +265,12 @@ local function read_from_tfm(specification)
--
constructors.enhanceparameters(parameters) -- official copies for us
--
- if constructors.resolvevirtualtoo then
+ if newtfmdata then
+ --
+ -- We do nothing as we assume flat tfm files. It would become real messy
+ -- otherwise and I don't have something for testing on my system anyway.
+ --
+ elseif constructors.resolvevirtualtoo then
fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here
local vfname = findbinfile(specification.name, 'ovf')
if vfname and vfname ~= "" then
@@ -145,21 +305,26 @@ local function read_from_tfm(specification)
end
end
--
- local allfeatures = tfmdata.shared.features or specification.features.normal
- constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm)
- if not features.encoding then
- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") -- context: encoding-name.*
- if filename and encoding and encodings.known and encodings.known[encoding] then
- features.encoding = encoding
- end
- end
- -- let's play safe:
+ -- This is for old times sake (and context specific) so we comment it. It has
+ -- to do with encoding prefixes (a context naming that was later adopted by
+ -- the lm/gyre project)
+ --
+ -- if not features.encoding then
+ -- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$")
+ -- if filename and encoding and encodings.known and encodings.known[encoding] then
+ -- features.encoding = encoding
+ -- end
+ -- end
+ --
+ -- Some afterthoughts:
+ --
properties.haskerns = true
properties.hasligatures = true
resources.unicodes = { }
resources.lookuptags = { }
--
depth[filename] = depth[filename] - 1
+ --
return tfmdata
else
depth[filename] = depth[filename] - 1
@@ -199,3 +364,366 @@ function readers.tfm(specification)
end
readers.ofm = readers.tfm
+
+-- The reencoding acts upon the 'reencode' feature which can have values 'auto' or
+-- an enc file. You can also specify a 'pfbfile' feature (but it defaults to the
+-- tfm filename) and a 'bitmap' feature. When no enc file is givven (auto) we will
+-- get the vectors from the pfb file.
+
+do
+
+ local outfiles = { }
+
+ local tfmcache = table.setmetatableindex(function(t,tfmdata)
+ local id = font.define(tfmdata)
+ t[tfmdata] = id
+ return id
+ end)
+
+ local encdone = table.setmetatableindex("table")
+
+ function tfm.reencode(tfmdata,specification)
+
+ local features = specification.features
+
+ if not features then
+ return
+ end
+
+ local features = features.normal
+
+ if not features then
+ return
+ end
+
+ local tfmfile = file.basename(tfmdata.name)
+ local encfile = features.reencode -- or features.enc
+ local pfbfile = features.pfbfile -- or features.pfb
+ local bitmap = features.bitmap -- or features.pk
+
+ if not encfile then
+ return
+ end
+
+ local pfbfile = outfiles[tfmfile]
+
+ if pfbfile == nil then
+ if bitmap then
+ pfbfile = false
+ elseif type(pfbfile) ~= "string" then
+ pfbfile = tfmfile
+ end
+ if type(pfbfile) == "string" then
+ pfbfile = file.addsuffix(pfbfile,"pfb")
+ -- pdf.mapline(tfmfile .. "<" .. pfbfile)
+ report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile)
+ else
+ report_tfm("using bitmap shapes for %a",tfmfile)
+ pfbfile = false -- use bitmap
+ end
+ outfiles[tfmfile] = pfbfile
+ end
+
+ local encoding = false
+ local vector = false
+
+ if type(pfbfile) == "string" then
+ local pfb = fonts.constructors.handlers.pfb
+ if pfb and pfb.loadvector then
+ local v, e = pfb.loadvector(pfbfile)
+ if v then
+ vector = v
+ end
+ if e then
+ encoding = e
+ end
+ end
+ end
+ if type(encfile) == "string" and encfile ~= "auto" then
+ encoding = fonts.encodings.load(file.addsuffix(encfile,"enc"))
+ if encoding then
+ encoding = encoding.vector
+ end
+ end
+ if not encoding then
+ report_tfm("bad encoding for %a, quitting",tfmfile)
+ return
+ end
+
+ local unicoding = fonts.encodings.agl and fonts.encodings.agl.unicodes
+ local virtualid = tfmcache[tfmdata]
+ local tfmdata = table.copy(tfmdata) -- good enough for small fonts
+ local characters = { }
+ local originals = tfmdata.characters
+ local indices = { }
+ local parentfont = { "font", 1 }
+ local private = fonts.constructors.privateoffset
+ local reported = encdone[tfmfile][encfile]
+
+ -- create characters table
+
+ local backmap = vector and table.swapped(vector)
+ local done = { } -- prevent duplicate
+
+ for index, name in sortedhash(encoding) do -- predictable order
+ local unicode = unicoding[name]
+ local original = originals[index]
+ if original then
+ if unicode then
+ original.unicode = unicode
+ else
+ unicode = private
+ private = private + 1
+ if not reported then
+ report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode)
+ end
+ end
+ characters[unicode] = original
+ indices[index] = unicode
+ original.name = name -- so one can lookup weird names
+ if backmap then
+ original.index = backmap[name]
+ else -- probably bitmap
+ original.commands = { parentfont, { "char", index } }
+ original.oindex = index
+ end
+ done[name] = true
+ elseif not done[name] then
+ report_tfm("bad index %a in font %a with name %a",index,tfmfile,name)
+ end
+ end
+
+ encdone[tfmfile][encfile] = true
+
+ -- redo kerns and ligatures
+
+ for k, v in next, characters do
+ local kerns = v.kerns
+ if kerns then
+ local t = { }
+ for k, v in next, kerns do
+ local i = indices[k]
+ if i then
+ t[i] = v
+ end
+ end
+ v.kerns = next(t) and t or nil
+ end
+ local ligatures = v.ligatures
+ if ligatures then
+ local t = { }
+ for k, v in next, ligatures do
+ local i = indices[k]
+ if i then
+ t[i] = v
+ v.char = indices[v.char]
+ end
+ end
+ v.ligatures = next(t) and t or nil
+ end
+ end
+
+ -- wrap up
+
+ tfmdata.fonts = { { id = virtualid } }
+ tfmdata.characters = characters
+ tfmdata.fullname = tfmdata.fullname or tfmdata.name
+ tfmdata.psname = file.nameonly(pfbfile or tfmdata.name)
+ tfmdata.filename = pfbfile
+ tfmdata.encodingbytes = 2
+ tfmdata.format = "type1"
+ tfmdata.tounicode = 1
+ tfmdata.embedding = "subset"
+ tfmdata.usedbitmap = bitmap and virtualid
+
+ return tfmdata
+ end
+
+end
+
+-- This code adds a ToUnicode vector for bitmap fonts. We don't bother about
+-- ranges because we have small fonts. it works ok with acrobat but fails with
+-- the other viewers (they get confused by the bitmaps I guess).
+
+do
+
+ local template = [[
+/CIDInit /ProcSet findresource begin
+ 12 dict begin
+ begincmap
+ /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def
+ /CMapName /TeX-bitmap-%s def
+ /CMapType 2 def
+ 1 begincodespacerange
+ <00> <FF>
+ endcodespacerange
+ %s beginbfchar
+%s
+ endbfchar
+ endcmap
+CMapName currentdict /CMap defineresource pop end
+end
+end
+]]
+
+ local flushstreamobject = lpdf and lpdf.flushstreamobject
+ local setfontattributes = pdf.setfontattributes
+
+ if not flushstreamobject then
+ flushstreamobject = function(data)
+ return pdf.obj {
+ immediate = true,
+ type = "stream",
+ string = data,
+ }
+ end
+ end
+
+ if not setfontattributes then
+ setfontattributes = function(id,data)
+ print(format("your luatex is too old so no tounicode bitmap font%i",id))
+ end
+ end
+
+ function tfm.addtounicode(tfmdata)
+ local id = tfmdata.usedbitmap
+ local map = { }
+ local char = { } -- no need for range, hardly used
+ for k, v in next, tfmdata.characters do
+ local index = v.oindex
+ local tounicode = v.tounicode
+ if index and tounicode then
+ map[index] = tounicode
+ end
+ end
+ for k, v in sortedhash(map) do
+ char[#char+1] = format("<%02X> <%s>",k,v)
+ end
+ char = concat(char,"\n")
+ local stream = format(template,id,id,#char,char)
+ local reference = flushstreamobject(stream,nil,true)
+ setfontattributes(id,format("/ToUnicode %i 0 R",reference))
+ end
+
+end
+
+-- Now we implement the regular features handlers. We need to convert the
+-- tfm specific structures to opentype structures. In basemode they are
+-- converted back so that is a bti of a waste but it's fast enough.
+
+do
+
+ local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
+ local noflags = { false, false, false, false }
+
+ enhancers["normalize features"] = function(data)
+ local ligatures = setmetatableindex("table")
+ local kerns = setmetatableindex("table")
+ local characters = data.characters
+ for u, c in next, characters do
+ local l = c.ligatures
+ local k = c.kerns
+ if l then
+ ligatures[u] = l
+ for u, v in next, l do
+ l[u] = { ligature = v.char }
+ end
+ c.ligatures = nil
+ end
+ if k then
+ kerns[u] = k
+ for u, v in next, k do
+ k[u] = v -- { v, 0 }
+ end
+ c.kerns = nil
+ end
+ end
+
+ for u, l in next, ligatures do
+ for k, v in next, l do
+ local vl = v.ligature
+ local dl = ligatures[vl]
+ if dl then
+ for kk, vv in next, dl do
+ v[kk] = vv -- table.copy(vv)
+ end
+ end
+ end
+ end
+
+ local features = {
+ gpos = { },
+ gsub = { },
+ }
+ local sequences = {
+ -- only filled ones
+ }
+ if next(ligatures) then
+ features.gsub.liga = everywhere
+ data.properties.hasligatures = true
+ sequences[#sequences+1] = {
+ features = {
+ liga = everywhere,
+ },
+ flags = noflags,
+ name = "s_s_0",
+ nofsteps = 1,
+ order = { "liga" },
+ type = "gsub_ligature",
+ steps = {
+ {
+ coverage = ligatures,
+ },
+ },
+ }
+ end
+ if next(kerns) then
+ features.gpos.kern = everywhere
+ data.properties.haskerns = true
+ sequences[#sequences+1] = {
+ features = {
+ kern = everywhere,
+ },
+ flags = noflags,
+ name = "p_s_0",
+ nofsteps = 1,
+ order = { "kern" },
+ type = "gpos_pair",
+ steps = {
+ {
+ format = "kern",
+ coverage = kerns,
+ },
+ },
+ }
+ end
+ data.resources.features = features
+ data.resources.sequences = sequences
+ data.shared.resources = data.shared.resources or resources
+ end
+
+end
+
+-- As with type one (afm) loading, we just use the opentype ones:
+
+registertfmfeature {
+ name = "mode",
+ description = "mode",
+ initializers = {
+ base = otf.modeinitializer,
+ node = otf.modeinitializer,
+ }
+}
+
+registertfmfeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ base = otf.basemodeinitializer,
+ node = otf.nodemodeinitializer,
+ },
+ processors = {
+ node = otf.featuresprocessor,
+ }
+}
diff --git a/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua b/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua
index 13acd16..793526f 100644
--- a/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua
+++ b/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua
@@ -1,3 +1,11 @@
+if not modules then modules = { } end modules ['luatex-fonts-demo-vf-1'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
local identifiers = fonts.hashes.identifiers
return function(specification)
diff --git a/src/fontloader/misc/fontloader-fonts-enc.lua b/src/fontloader/misc/fontloader-fonts-enc.lua
index 2e1c6a4..c076d59 100644
--- a/src/fontloader/misc/fontloader-fonts-enc.lua
+++ b/src/fontloader/misc/fontloader-fonts-enc.lua
@@ -11,19 +11,66 @@ if context then
os.exit()
end
-local fonts = fonts
-fonts.encodings = { }
-fonts.encodings.agl = { }
-fonts.encodings.known = { }
+local fonts = fonts
+local encodings = { }
+fonts.encodings = encodings
+encodings.agl = { }
+encodings.known = { }
-setmetatable(fonts.encodings.agl, { __index = function(t,k)
+setmetatable(encodings.agl, { __index = function(t,k)
if k == "unicodes" then
texio.write(" <loading (extended) adobe glyph list>")
local unicodes = dofile(resolvers.findfile("font-age.lua"))
- fonts.encodings.agl = { unicodes = unicodes }
+ encodings.agl = { unicodes = unicodes }
return unicodes
else
return nil
end
end })
+-- adapted for generic
+
+encodings.cache = containers.define("fonts", "enc", encodings.version, true)
+
+function encodings.load(filename)
+ local name = file.removesuffix(filename)
+ local data = containers.read(encodings.cache,name)
+ if data then
+ return data
+ end
+ local vector, tag, hash, unicodes = { }, "", { }, { }
+ local foundname = resolvers.findfile(filename,'enc')
+ if foundname and foundname ~= "" then
+ local ok, encoding, size = resolvers.loadbinfile(foundname)
+ if ok and encoding then
+ encoding = string.gsub(encoding,"%%(.-)\n","")
+ local unicoding = encodings.agl.unicodes
+ local tag, vec = string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
+ local i = 0
+ for ch in string.gmatch(vec,"/([%a%d%.]+)") do
+ if ch ~= ".notdef" then
+ vector[i] = ch
+ if not hash[ch] then
+ hash[ch] = i
+ else
+ -- duplicate, play safe for tex ligs and take first
+ end
+ local u = unicoding[ch]
+ if u then
+ unicodes[u] = i
+ end
+ end
+ i = i + 1
+ end
+ end
+ end
+ local data = {
+ name = name,
+ tag = tag,
+ vector = vector,
+ hash = hash,
+ unicodes = unicodes
+ }
+ return containers.write(encodings.cache, name, data)
+end
+
diff --git a/src/fontloader/misc/fontloader-fonts.lua b/src/fontloader/misc/fontloader-fonts.lua
index 83d52d9..41b95d9 100644
--- a/src/fontloader/misc/fontloader-fonts.lua
+++ b/src/fontloader/misc/fontloader-fonts.lua
@@ -230,7 +230,6 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('luatex-fonts-syn.lua')
- loadmodule('font-tfm.lua')
loadmodule('font-oti.lua')
-- These are the old loader and processing modules. These use the built-in font loader and
@@ -266,6 +265,10 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('font-one.lua') -- was font-afm.lua
loadmodule('font-afk.lua')
+ -- traditional code
+
+ loadmodule('font-tfm.lua')
+
-- common code
loadmodule('font-lua.lua')
diff --git a/src/fontloader/misc/fontloader-l-table.lua b/src/fontloader/misc/fontloader-l-table.lua
index 552097e..d1e0592 100644
--- a/src/fontloader/misc/fontloader-l-table.lua
+++ b/src/fontloader/misc/fontloader-l-table.lua
@@ -673,6 +673,8 @@ local function do_serialize(root,name,depth,level,indexed)
else
handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g
end
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
if hexify then
handle(format("%s %s=0x%X,",depth,k,v))
@@ -695,6 +697,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%q,",depth,k,v))
else
@@ -710,6 +714,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]={},",depth,k and "true" or "false"))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s={},",depth,k))
else
@@ -726,6 +732,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
else
@@ -746,6 +754,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
else
@@ -763,6 +773,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=load(%q),",depth,k,f))
else
@@ -778,6 +790,8 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk == "boolean" then
handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
+ elseif tk ~= "string" then
+ -- ignore
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%q,",depth,k,tostring(v)))
else
@@ -1165,7 +1179,7 @@ function table.has_one_entry(t)
return t and next(t,next(t)) == nil
end
--- new
+-- new (rather basic, not indexed and nested)
function table.loweredkeys(t) -- maybe utf
local l = { }
diff --git a/src/fontloader/misc/fontloader-mplib.lua b/src/fontloader/misc/fontloader-mplib.lua
index fd6eb97..976bb59 100644
--- a/src/fontloader/misc/fontloader-mplib.lua
+++ b/src/fontloader/misc/fontloader-mplib.lua
@@ -352,7 +352,7 @@ else
return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
end
- local function concat(px, py) -- no tx, ty here
+ local function concatinated(px, py) -- no tx, ty here
return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
end
@@ -401,29 +401,29 @@ else
for i=1,#path do
pth = path[i]
if not ith then
- pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord))
+ pdf_literalcode("%f %f m",concatinated(pth.x_coord,pth.y_coord))
elseif curved(ith,pth) then
- local a, b = concat(ith.right_x,ith.right_y)
- local c, d = concat(pth.left_x,pth.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
+ local a, b = concatinated(ith.right_x,ith.right_y)
+ local c, d = concatinated(pth.left_x,pth.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(pth.x_coord, pth.y_coord))
else
- pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord))
+ pdf_literalcode("%f %f l",concatinated(pth.x_coord, pth.y_coord))
end
ith = pth
end
if not open then
local one = path[1]
if curved(pth,one) then
- local a, b = concat(pth.right_x,pth.right_y)
- local c, d = concat(one.left_x,one.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
+ local a, b = concatinated(pth.right_x,pth.right_y)
+ local c, d = concatinated(one.left_x,one.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(one.x_coord, one.y_coord))
else
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord))
end
elseif #path == 1 then
-- special case .. draw point
local one = path[1]
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord))
end
return t
end
diff --git a/src/fontloader/misc/fontloader-plain-tfm.lua b/src/fontloader/misc/fontloader-plain-tfm.lua
new file mode 100644
index 0000000..4a08fb4
--- /dev/null
+++ b/src/fontloader/misc/fontloader-plain-tfm.lua
@@ -0,0 +1,120 @@
+if not modules then modules = { } end modules ['luatex-plain-tfm'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- \font\foo=file:luatex-plain-tfm.lua:tfm=csr10;enc=csr;pfb=csr10 at 12pt
+-- \font\bar=file:luatex-plain-tfm.lua:tfm=csr10;enc=csr at 12pt
+--
+-- \foo Ć”Ć¤ÄÄÄ›Ć­ÄŗÄ¾ÅˆĆ³Ć“Å•Å™Å”Å„ĆŗĆ½Å¾ ff ffi \input tufte\par
+-- \bar Ć”Ć¤ÄÄÄ›Ć­ÄŗÄ¾ÅˆĆ³Ć“Å•Å™Å”Å„ĆŗĆ½Å¾ ff ffi \input tufte\par
+
+local outfiles = { }
+
+return function(specification)
+
+ local size = specification.size
+ local name = specification.name
+ local feat = specification.features and specification.features.normal
+
+ if not feat then
+ return
+ end
+
+ local tfm = feat.tfm
+ local enc = feat.enc or tfm
+ local pfb = feat.pfb
+
+ if not tfm then
+ return
+ end
+
+ local tfmfile = tfm .. ".tfm"
+ local encfile = enc .. ".enc"
+
+ local tfmdata, id = fonts.constructors.readanddefine("file:"..tfmfile,size)
+
+ local encoding = fonts.encodings.load(encfile)
+ if encoding then
+ encoding = encoding.hash
+ else
+ encoding = false
+ end
+
+ local unicoding = fonts.encodings.agl and fonts.encodings.agl.unicodes
+
+ if tfmdata and encoding and unicoding then
+
+ tfmdata = table.copy(tfmdata) -- good enough for small fonts
+
+ local characters = { }
+ local originals = tfmdata.characters
+ local indices = { }
+ local parentfont = { "font", 1 }
+ local private = fonts.constructors.privateoffset
+
+ -- create characters table
+
+ for name, index in table.sortedhash(encoding) do -- predictable order
+ local unicode = unicoding[name]
+ local original = originals[index]
+ if not unicode then
+ unicode = private
+ private = private + 1
+ report_tfm("glyph %a in font %a gets private unicode %U",name,tfmfile,private)
+ end
+ characters[unicode] = original
+ indices[index] = unicode
+ original.name = name -- so one can lookup weird names
+ original.commands = { parentfont, { "char", index } }
+ end
+
+ -- redo kerns and ligatures
+
+ for k, v in next, characters do
+ local kerns = v.kerns
+ if kerns then
+ local t = { }
+ for k, v in next, kerns do
+ local i = indices[k]
+ t[i] = v
+ end
+ v.kerns = t
+ end
+ local ligatures = v.ligatures
+ if ligatures then
+ local t = { }
+ for k, v in next, ligatures do
+ t[indices[k]] = v
+ v.char = indices[v.char]
+ end
+ v.ligatures = t
+ end
+ end
+
+ -- wrap up
+
+ tfmdata.fonts = { { id = id } }
+ tfmdata.characters = characters
+
+ -- resources
+
+ local outfile = outfiles[tfmfile]
+
+ if outfile == nil then
+ if pfb then
+ outfile = pfb .. ".pfb"
+ pdf.mapline(tfm .. "<" .. outfile)
+ else
+ outfile = false
+ end
+ outfiles[tfmfile] = outfile
+ end
+
+ end
+
+ return tfmdata
+end
diff --git a/src/fontloader/misc/fontloader-plain.tex b/src/fontloader/misc/fontloader-plain.tex
index 99347ed..0a806c7 100644
--- a/src/fontloader/misc/fontloader-plain.tex
+++ b/src/fontloader/misc/fontloader-plain.tex
@@ -17,7 +17,9 @@
\input luatex-pdf \relax
\fi
-\pdfoutput 1
+\outputmode 1
+
+% \outputmode 0 \magnification\magstep5
% We set the page dimensions because otherwise the backend does weird things
% when we have for instance this on a line of its own:
@@ -31,8 +33,8 @@
% has to deal with the lack of a page concept on tex by some guessing. Normally
% a macro package will set the dimensions to something reasonable anyway.
-\pagewidth 8.5in
-\pageheight 11.0in
+\pagewidth 8.5truein
+\pageheight 11.0truein
% We load some code at runtime:
diff --git a/src/fontloader/misc/fontloader-test.tex b/src/fontloader/misc/fontloader-test.tex
index 0bb752b..2aa4f22 100644
--- a/src/fontloader/misc/fontloader-test.tex
+++ b/src/fontloader/misc/fontloader-test.tex
@@ -158,4 +158,16 @@ $\sin{x}$
% \textdir TRT\amiri ŲØŁŲ³Ł’Ł…Ł Ų§Ł„Ł„Ł‘ŁŽŁ€Ł‡Ł Ų§Ł„Ų±Ł‘ŁŽā€ŒŲ­Ł’Ł…ŁŽŁ€Ł°Ł†Ł Ų§Ł„Ų±Ł‘ŁŽā€ŒŲ­ŁŁŠŁ…Ł
% \egroup
+% assumes csr10.tfm csr10.pfb csr.enc to be present
+
+% \font\foo=file:luatex-plain-tfm.lua:tfm=csr10;enc=csr;pfb=csr10 at 12pt
+%
+% \foo Ć”Ć¤ÄÄÄ›Ć­ÄŗÄ¾ÅˆĆ³Ć“Å•Å™Å”Å„ĆŗĆ½Å¾ ff ffi
+
+% \font\foo=file:csr10.tfm:reencode=csr
+% \font\foo=file:csr10.tfm:reencode=csr;bitmap=yes % use map file
+% \font\foo=file:csr10.tfm:reencode=auto
+%
+% \foo Ć”Ć¤ÄÄÄ›Ć­ÄŗÄ¾ÅˆĆ³Ć“Å•Å™Å”Å„ĆŗĆ½Å¾ ff ffi \input tufte\par
+
\end
diff --git a/src/fontloader/misc/fontloader-util-fil.lua b/src/fontloader/misc/fontloader-util-fil.lua
index 28c92c7..47d9d03 100644
--- a/src/fontloader/misc/fontloader-util-fil.lua
+++ b/src/fontloader/misc/fontloader-util-fil.lua
@@ -90,7 +90,8 @@ end
function files.readinteger1(f) -- one byte
local n = byte(f:read(1))
if n >= 0x80 then
- return n - 0xFF - 1
+ -- return n - 0xFF - 1
+ return n - 0x100
else
return n
end
@@ -109,7 +110,8 @@ function files.readinteger2(f)
local a, b = byte(f:read(2),1,2)
local n = 0x100 * a + b
if n >= 0x8000 then
- return n - 0xFFFF - 1
+ -- return n - 0xFFFF - 1
+ return n - 0x10000
else
return n
end
@@ -120,6 +122,17 @@ function files.readcardinal3(f)
return 0x10000 * a + 0x100 * b + c
end
+function files.readinteger3(f)
+ local a, b, c = byte(f:read(3),1,3)
+ local n = 0x10000 * a + 0x100 * b + c
+ if n >= 0x80000 then
+ -- return n - 0xFFFFFF - 1
+ return n - 0x1000000
+ else
+ return n
+ end
+end
+
function files.readcardinal4(f)
local a, b, c, d = byte(f:read(4),1,4)
return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
@@ -129,7 +142,8 @@ function files.readinteger4(f)
local a, b, c, d = byte(f:read(4),1,4)
local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
if n >= 0x8000000 then
- return n - 0xFFFFFFFF - 1
+ -- return n - 0xFFFFFFFF - 1
+ return n - 0x100000000
else
return n
end
@@ -139,7 +153,8 @@ function files.readfixed4(f)
local a, b, c, d = byte(f:read(4),1,4)
local n = 0x100 * a + b
if n >= 0x8000 then
- return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
+ -- return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
+ return n - 0x10000 + (0x100 * c + d)/0xFFFF
else
return n + (0x100 * c + d)/0xFFFF
end
diff --git a/src/fontloader/misc/fontloader-util-str.lua b/src/fontloader/misc/fontloader-util-str.lua
index 28b75db..a54a4aa 100644
--- a/src/fontloader/misc/fontloader-util-str.lua
+++ b/src/fontloader/misc/fontloader-util-str.lua
@@ -824,6 +824,8 @@ end
-- extensions : %!tag!
+-- can be made faster but not called that often
+
local builder = Cs { "start",
start = (
(
@@ -852,10 +854,10 @@ local builder = Cs { "start",
+ V("a") -- new
+ V("A") -- new
+ V("j") + V("J") -- stripped e E
- + V("m") + V("M") -- new
+ + V("m") + V("M") -- new (formatted number)
+ V("z") -- new
--
- -- + V("?") -- ignores probably messed up %
+ -- + V("?") -- ignored, probably messed up %
)
+ V("*")
)
diff --git a/src/fontloader/runtime/fontloader-basics-gen.lua b/src/fontloader/runtime/fontloader-basics-gen.lua
index 2a68b1c..871e548 100644
--- a/src/fontloader/runtime/fontloader-basics-gen.lua
+++ b/src/fontloader/runtime/fontloader-basics-gen.lua
@@ -97,6 +97,7 @@ local remapper = {
-- fea = "font feature files", -- no longer supported
pfb = "type1 fonts", -- needed for vector loading
afm = "afm",
+ enc = "enc files",
}
function resolvers.findfile(name,fileformat)
diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua
index 9785988..e6738ea 100644
--- a/src/fontloader/runtime/fontloader-reference.lua
+++ b/src/fontloader/runtime/fontloader-reference.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 06/15/16 20:18:05
+-- merge date : 07/13/16 15:09:54
do -- begin closure to overcome local limits and interference
@@ -1487,6 +1487,7 @@ local function do_serialize(root,name,depth,level,indexed)
else
handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
end
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
if hexify then
handle(format("%s %s=0x%X,",depth,k,v))
@@ -1509,6 +1510,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%q,",depth,k,v))
else
@@ -1524,6 +1526,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]={},",depth,k and "true" or "false"))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s={},",depth,k))
else
@@ -1540,6 +1543,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
else
@@ -1560,6 +1564,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
else
@@ -1576,6 +1581,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=load(%q),",depth,k,f))
else
@@ -1591,6 +1597,7 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif tk=="boolean" then
handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
+ elseif tk~="string" then
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
handle(format("%s %s=%q,",depth,k,tostring(v)))
else
@@ -4161,7 +4168,7 @@ end
function files.readinteger1(f)
local n=byte(f:read(1))
if n>=0x80 then
- return n-0xFF-1
+ return n-0x100
else
return n
end
@@ -4177,7 +4184,7 @@ function files.readinteger2(f)
local a,b=byte(f:read(2),1,2)
local n=0x100*a+b
if n>=0x8000 then
- return n-0xFFFF-1
+ return n-0x10000
else
return n
end
@@ -4186,6 +4193,15 @@ function files.readcardinal3(f)
local a,b,c=byte(f:read(3),1,3)
return 0x10000*a+0x100*b+c
end
+function files.readinteger3(f)
+ local a,b,c=byte(f:read(3),1,3)
+ local n=0x10000*a+0x100*b+c
+ if n>=0x80000 then
+ return n-0x1000000
+ else
+ return n
+ end
+end
function files.readcardinal4(f)
local a,b,c,d=byte(f:read(4),1,4)
return 0x1000000*a+0x10000*b+0x100*c+d
@@ -4194,7 +4210,7 @@ function files.readinteger4(f)
local a,b,c,d=byte(f:read(4),1,4)
local n=0x1000000*a+0x10000*b+0x100*c+d
if n>=0x8000000 then
- return n-0xFFFFFFFF-1
+ return n-0x100000000
else
return n
end
@@ -4203,7 +4219,7 @@ function files.readfixed4(f)
local a,b,c,d=byte(f:read(4),1,4)
local n=0x100*a+b
if n>=0x8000 then
- return n-0xFFFF-1+(0x100*c+d)/0xFFFF
+ return n-0x10000+(0x100*c+d)/0xFFFF
else
return n+(0x100*c+d)/0xFFFF
end
@@ -4311,6 +4327,7 @@ local remapper={
cidmap="cid maps",
pfb="type1 fonts",
afm="afm",
+ enc="enc files",
}
function resolvers.findfile(name,fileformat)
name=string.gsub(name,"\\","/")
@@ -5673,7 +5690,7 @@ if not modules then modules={} end modules ['font-con']={
license="see context related readme files"
}
local next,tostring,rawget=next,tostring,rawget
-local format,match,lower,gsub=string.format,string.match,string.lower,string.gsub
+local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find
local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
local derivetable=table.derive
local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
@@ -5693,89 +5710,6 @@ constructors.version=1.01
constructors.cache=containers.define("fonts","constructors",constructors.version,false)
constructors.privateoffset=0xF0000
constructors.cacheintex=true
-constructors.keys={
- properties={
- encodingbytes="number",
- embedding="number",
- cidinfo={},
- format="string",
- fontname="string",
- fullname="string",
- filename="filename",
- psname="string",
- name="string",
- virtualized="boolean",
- hasitalics="boolean",
- autoitalicamount="basepoints",
- nostackmath="boolean",
- noglyphnames="boolean",
- mode="string",
- hasmath="boolean",
- mathitalics="boolean",
- textitalics="boolean",
- finalized="boolean",
- },
- parameters={
- mathsize="number",
- scriptpercentage="float",
- scriptscriptpercentage="float",
- units="cardinal",
- designsize="scaledpoints",
- expansion={
- stretch="integerscale",
- shrink="integerscale",
- step="integerscale",
- auto="boolean",
- },
- protrusion={
- auto="boolean",
- },
- slantfactor="float",
- extendfactor="float",
- factor="float",
- hfactor="float",
- vfactor="float",
- size="scaledpoints",
- units="scaledpoints",
- scaledpoints="scaledpoints",
- slantperpoint="scaledpoints",
- spacing={
- width="scaledpoints",
- stretch="scaledpoints",
- shrink="scaledpoints",
- extra="scaledpoints",
- },
- xheight="scaledpoints",
- quad="scaledpoints",
- ascender="scaledpoints",
- descender="scaledpoints",
- synonyms={
- space="spacing.width",
- spacestretch="spacing.stretch",
- spaceshrink="spacing.shrink",
- extraspace="spacing.extra",
- x_height="xheight",
- space_stretch="spacing.stretch",
- space_shrink="spacing.shrink",
- extra_space="spacing.extra",
- em="quad",
- ex="xheight",
- slant="slantperpoint",
- },
- },
- description={
- width="basepoints",
- height="basepoints",
- depth="basepoints",
- boundingbox={},
- },
- character={
- width="scaledpoints",
- height="scaledpoints",
- depth="scaledpoints",
- italic="scaledpoints",
- },
-}
local designsizes=allocate()
constructors.designsizes=designsizes
local loadedfonts=allocate()
@@ -5913,6 +5847,23 @@ local function mathkerns(v,vdelta)
end
return k
end
+local psfake=0
+local function fixedpsname(psname,fallback)
+ local usedname=psname
+ if psname and psname~="" then
+ if find(psname," ") then
+ usedname=gsub(psname,"[%s]+","-")
+ else
+ end
+ elseif not fallback or fallback=="" then
+ psfake=psfake+1
+ psname="fakename-"..psfake
+ else
+ psname=fallback
+ usedname=gsub(psname,"[^a-zA-Z0-9]+","-")
+ end
+ return usedname,psname~=usedname
+end
function constructors.scale(tfmdata,specification)
local target={}
if tonumber(specification) then
@@ -5986,14 +5937,12 @@ function constructors.scale(tfmdata,specification)
target.cidinfo=properties.cidinfo
target.format=properties.format
target.cache=constructors.cacheintex and "yes" or "renew"
- local fontname=properties.fontname or tfmdata.fontname
- local fullname=properties.fullname or tfmdata.fullname
- local filename=properties.filename or tfmdata.filename
- local psname=properties.psname or tfmdata.psname
+ local fontname=properties.fontname or tfmdata.fontname
+ local fullname=properties.fullname or tfmdata.fullname
+ local filename=properties.filename or tfmdata.filename
+ local psname=properties.psname or tfmdata.psname
local name=properties.name or tfmdata.name
- if not psname or psname=="" then
- psname=fontname or (fullname and fonts.names.cleanname(fullname))
- end
+ local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename))
target.fontname=fontname
target.fullname=fullname
target.filename=filename
@@ -6106,8 +6055,9 @@ function constructors.scale(tfmdata,specification)
end
end
if trace_defining then
- report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a",
- name,fullname,filename,hdelta,vdelta,hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
+ report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a",
+ name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta,
+ hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
end
constructors.beforecopyingcharacters(target,tfmdata)
local sharedkerns={}
@@ -6849,19 +6799,61 @@ if context then
os.exit()
end
local fonts=fonts
-fonts.encodings={}
-fonts.encodings.agl={}
-fonts.encodings.known={}
-setmetatable(fonts.encodings.agl,{ __index=function(t,k)
+local encodings={}
+fonts.encodings=encodings
+encodings.agl={}
+encodings.known={}
+setmetatable(encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
texio.write(" <loading (extended) adobe glyph list>")
local unicodes=dofile(resolvers.findfile("font-age.lua"))
- fonts.encodings.agl={ unicodes=unicodes }
+ encodings.agl={ unicodes=unicodes }
return unicodes
else
return nil
end
end })
+encodings.cache=containers.define("fonts","enc",encodings.version,true)
+function encodings.load(filename)
+ local name=file.removesuffix(filename)
+ local data=containers.read(encodings.cache,name)
+ if data then
+ return data
+ end
+ local vector,tag,hash,unicodes={},"",{},{}
+ local foundname=resolvers.findfile(filename,'enc')
+ if foundname and foundname~="" then
+ local ok,encoding,size=resolvers.loadbinfile(foundname)
+ if ok and encoding then
+ encoding=string.gsub(encoding,"%%(.-)\n","")
+ local unicoding=encodings.agl.unicodes
+ local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
+ local i=0
+ for ch in string.gmatch(vec,"/([%a%d%.]+)") do
+ if ch~=".notdef" then
+ vector[i]=ch
+ if not hash[ch] then
+ hash[ch]=i
+ else
+ end
+ local u=unicoding[ch]
+ if u then
+ unicodes[u]=i
+ end
+ end
+ i=i+1
+ end
+ end
+ end
+ local data={
+ name=name,
+ tag=tag,
+ vector=vector,
+ hash=hash,
+ unicodes=unicodes
+ }
+ return containers.write(encodings.cache,name,data)
+end
end -- closure
@@ -7033,7 +7025,7 @@ local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.m
local floor=math.floor
local formatters=string.formatters
local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end)
-local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_unimapping=v end)
+local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_mapping=v end)
local report_fonts=logs.reporter("fonts","loading")
local force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end)
local fonts=fonts or {}
@@ -7149,6 +7141,9 @@ function mappings.addtounicode(data,filename,checklookups)
local resources=data.resources
local unicodes=resources.unicodes
if not unicodes then
+ if trace_mapping then
+ report_fonts("no unicode list, quitting tounicode for %a",filename)
+ end
return
end
local properties=data.properties
@@ -7337,8 +7332,8 @@ function mappings.addtounicode(data,filename,checklookups)
end
if trace_mapping then
for unic,glyph in table.sortedhash(descriptions) do
- local name=glyph.name
- local index=glyph.index
+ local name=glyph.name or "-"
+ local index=glyph.index or 0
local unicode=glyph.unicode
if unicode then
if type(unicode)=="table" then
@@ -7441,164 +7436,6 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-tfm']={
- 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 next=next
-local match=string.match
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end)
-local report_defining=logs.reporter("fonts","defining")
-local report_tfm=logs.reporter("fonts","tfm loading")
-local findbinfile=resolvers.findbinfile
-local fonts=fonts
-local handlers=fonts.handlers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local encodings=fonts.encodings
-local tfm=constructors.handlers.tfm
-tfm.version=1.000
-tfm.maxnestingdepth=5
-tfm.maxnestingsize=65536*1024
-local tfmfeatures=constructors.features.tfm
-constructors.resolvevirtualtoo=false
-fonts.formats.tfm="type1"
-fonts.formats.ofm="type1"
-function tfm.setfeatures(tfmdata,features)
- local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
- if okay then
- return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
- else
- return {}
- end
-end
-local depth={}
-local function read_from_tfm(specification)
- local filename=specification.filename
- local size=specification.size
- depth[filename]=(depth[filename] or 0)+1
- if trace_defining then
- report_defining("loading tfm file %a at size %s",filename,size)
- end
- local tfmdata=font.read_tfm(filename,size)
- if tfmdata then
- local features=specification.features and specification.features.normal or {}
- local resources=tfmdata.resources or {}
- local properties=tfmdata.properties or {}
- local parameters=tfmdata.parameters or {}
- local shared=tfmdata.shared or {}
- properties.name=tfmdata.name
- properties.fontname=tfmdata.fontname
- properties.psname=tfmdata.psname
- properties.filename=specification.filename
- properties.format=fonts.formats.tfm
- parameters.size=size
- tfmdata.properties=properties
- tfmdata.resources=resources
- tfmdata.parameters=parameters
- tfmdata.shared=shared
- shared.rawdata={}
- shared.features=features
- shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
- parameters.slant=parameters.slant or parameters[1] or 0
- parameters.space=parameters.space or parameters[2] or 0
- parameters.space_stretch=parameters.space_stretch or parameters[3] or 0
- parameters.space_shrink=parameters.space_shrink or parameters[4] or 0
- parameters.x_height=parameters.x_height or parameters[5] or 0
- parameters.quad=parameters.quad or parameters[6] or 0
- parameters.extra_space=parameters.extra_space or parameters[7] or 0
- constructors.enhanceparameters(parameters)
- if constructors.resolvevirtualtoo then
- fonts.loggers.register(tfmdata,file.suffix(filename),specification)
- local vfname=findbinfile(specification.name,'ovf')
- if vfname and vfname~="" then
- local vfdata=font.read_vf(vfname,size)
- if vfdata then
- local chars=tfmdata.characters
- for k,v in next,vfdata.characters do
- chars[k].commands=v.commands
- end
- properties.virtualized=true
- tfmdata.fonts=vfdata.fonts
- tfmdata.type="virtual"
- local fontlist=vfdata.fonts
- local name=file.nameonly(filename)
- for i=1,#fontlist do
- local n=fontlist[i].name
- local s=fontlist[i].size
- local d=depth[filename]
- s=constructors.scaled(s,vfdata.designsize)
- if d>tfm.maxnestingdepth then
- report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
- fontlist[i]={ id=0 }
- elseif (d>1) and (s>tfm.maxnestingsize) then
- report_defining("virtual font %a exceeds size %s",n,s)
- fontlist[i]={ id=0 }
- else
- local t,id=fonts.constructors.readanddefine(n,s)
- fontlist[i]={ id=id }
- end
- end
- end
- end
- end
- local allfeatures=tfmdata.shared.features or specification.features.normal
- constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm)
- if not features.encoding then
- local encoding,filename=match(properties.filename,"^(.-)%-(.*)$")
- if filename and encoding and encodings.known and encodings.known[encoding] then
- features.encoding=encoding
- end
- end
- properties.haskerns=true
- properties.hasligatures=true
- resources.unicodes={}
- resources.lookuptags={}
- depth[filename]=depth[filename]-1
- return tfmdata
- else
- depth[filename]=depth[filename]-1
- end
-end
-local function check_tfm(specification,fullname)
- local foundname=findbinfile(fullname,'tfm') or ""
- if foundname=="" then
- foundname=findbinfile(fullname,'ofm') or ""
- end
- if foundname=="" then
- foundname=fonts.names.getfilename(fullname,"tfm") or ""
- end
- if foundname~="" then
- specification.filename=foundname
- specification.format="ofm"
- return read_from_tfm(specification)
- elseif trace_defining then
- report_defining("loading tfm with name %a fails",specification.name)
- end
-end
-readers.check_tfm=check_tfm
-function readers.tfm(specification)
- local fullname=specification.filename or ""
- if fullname=="" then
- local forced=specification.forced or ""
- if forced~="" then
- fullname=specification.name.."."..forced
- else
- fullname=specification.name
- end
- end
- return check_tfm(specification,fullname)
-end
-readers.ofm=readers.tfm
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
if not modules then modules={} end modules ['font-oti']={
version=1.001,
comment="companion to font-ini.mkiv",
@@ -7625,6 +7462,7 @@ local function setmode(tfmdata,value)
tfmdata.properties.mode=lower(value)
end
end
+otf.modeinitializer=setmode
local function setlanguage(tfmdata,value)
if value then
local cleanvalue=lower(value)
@@ -11355,10 +11193,15 @@ local function readcoverage(f,offset,simple)
end
return coverage
end
-local function readclassdef(f,offset)
+local function readclassdef(f,offset,preset)
setposition(f,offset)
local classdefformat=readushort(f)
local classdef={}
+ if type(preset)=="number" then
+ for k=0,preset-1 do
+ classdef[k]=1
+ end
+ end
if classdefformat==1 then
local index=readushort(f)
local nofclassdef=readushort(f)
@@ -11380,6 +11223,13 @@ local function readclassdef(f,offset)
else
report("unknown classdef format %a ",classdefformat)
end
+ if type(preset)=="table" then
+ for k in next,preset do
+ if not classdef[k] then
+ classdef[k]=1
+ end
+ end
+ end
return classdef
end
local function classtocoverage(defs)
@@ -11479,7 +11329,7 @@ local function covered(subset,all)
end
return used
end
-local function readlookuparray(f,noflookups)
+local function readlookuparray(f,noflookups,nofcurrent)
local lookups={}
if noflookups>0 then
local length=0
@@ -11522,7 +11372,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
for i=2,nofcurrent do
current[i]={ readushort(f) }
end
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1]={
current=current,
lookups=lookups
@@ -11544,7 +11394,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
local rules={}
if subclasssets then
coverage=readcoverage(f,tableoffset+coverage)
- currentclassdef=readclassdef(f,tableoffset+currentclassdef)
+ currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
for class=1,#subclasssets do
local offset=subclasssets[class]
@@ -11563,7 +11413,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
for i=2,nofcurrent do
current[i]=currentclasses[readushort(f)+1]
end
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1]={
current=current,
lookups=lookups
@@ -11587,7 +11437,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n
elseif subtype==3 then
local current=readarray(f)
local noflookups=readushort(f)
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,#current)
current=readcoveragearray(f,tableoffset,current,true)
return {
format="coverage",
@@ -11642,7 +11492,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
end
end
local noflookups=readushort(f)
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1]={
before=before,
current=current,
@@ -11668,9 +11518,9 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local rules={}
if subclasssets then
local coverage=readcoverage(f,tableoffset+coverage)
- local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef)
- local currentclassdef=readclassdef(f,tableoffset+currentclassdef)
- local afterclassdef=readclassdef(f,tableoffset+afterclassdef)
+ local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs)
+ local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
+ local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs)
local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs)
local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs)
@@ -11707,7 +11557,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
end
end
local noflookups=readushort(f)
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,nofcurrent)
rules[#rules+1]={
before=before,
current=current,
@@ -11735,7 +11585,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local current=readarray(f)
local after=readarray(f)
local noflookups=readushort(f)
- local lookups=readlookuparray(f,noflookups)
+ local lookups=readlookuparray(f,noflookups,#current)
before=readcoveragearray(f,tableoffset,before,true)
current=readcoveragearray(f,tableoffset,current,true)
after=readcoveragearray(f,tableoffset,after,true)
@@ -12061,8 +11911,8 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local nofclasses2=readushort(f)
local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
coverage=readcoverage(f,tableoffset+coverage)
- classdef1=readclassdef(f,tableoffset+classdef1)
- classdef2=readclassdef(f,tableoffset+classdef2)
+ classdef1=readclassdef(f,tableoffset+classdef1,coverage)
+ classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs)
local usedcoverage={}
for g1,c1 in next,classdef1 do
if coverage[g1] then
@@ -14090,6 +13940,7 @@ function readers.getcomponents(fontdata)
end
end
end
+readers.unifymissing=unifymissing
function readers.rehash(fontdata,hashmethod)
if not (fontdata and fontdata.glyphs) then
return
@@ -15363,7 +15214,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.023
+otf.version=3.025
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
@@ -15541,7 +15392,7 @@ function otf.load(filename,sub,featurefile)
collectgarbage("collect")
end
stoptiming(otfreaders)
- if elapsedtime then
+ if elapsedtime then
report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders))
end
if cleanup>3 then
@@ -15703,13 +15554,13 @@ local function copytotfm(data,cache_id)
spaceunits,spacer=charwidth,"charwidth"
end
end
- spaceunits=tonumber(spaceunits) or 500
+ spaceunits=tonumber(spaceunits) or units/2
parameters.slant=0
- parameters.space=spaceunits
+ parameters.space=spaceunits
parameters.space_stretch=1*units/2
- parameters.space_shrink=1*units/3
- parameters.x_height=2*units/5
- parameters.quad=units
+ parameters.space_shrink=1*units/3
+ parameters.x_height=2*units/5
+ parameters.quad=units
if spaceunits<2*units/5 then
end
if italicangle and italicangle~=0 then
@@ -16119,7 +15970,7 @@ local function registerbasehash(tfmdata)
basehash[hash]=base
end
properties.basehash=base
- properties.fullname=properties.fullname.."-"..base
+ properties.fullname=(properties.fullname or properties.name).."-"..base
applied={}
end
local function registerbasefeature(feature,value)
@@ -16187,6 +16038,10 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local trace_singles=trace_baseinit and trace_singles
local trace_alternatives=trace_baseinit and trace_alternatives
local trace_ligatures=trace_baseinit and trace_ligatures
+ if not changed then
+ changed={}
+ tfmdata.changed=changed
+ end
for i=1,#lookuplist do
local sequence=lookuplist[i]
local steps=sequence.steps
@@ -16340,7 +16195,8 @@ local function featuresinitializer(tfmdata,value)
local properties=tfmdata.properties
local script=properties.script
local language=properties.language
- local rawfeatures=rawdata.resources.features
+ local rawresources=rawdata.resources
+ local rawfeatures=rawresources and rawresources.features
local basesubstitutions=rawfeatures and rawfeatures.gsub
local basepositionings=rawfeatures and rawfeatures.gpos
if basesubstitutions or basepositionings then
@@ -16411,7 +16267,7 @@ local registertracker=trackers.register
local trace_injections=false registertracker("fonts.injections",function(v) trace_injections=v end)
local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end)
local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end)
-local trace_spaces=false registertracker("otf.spaces",function(v) trace_spaces=v end)
+local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end)
local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end)
local report_injections=logs.reporter("fonts","injections")
local report_spaces=logs.reporter("fonts","spaces")
@@ -17293,6 +17149,10 @@ local function inject_everything(head,where)
nofmarks=nofmarks+1
marks[nofmarks]=current
else
+local yoffset=i.yoffset
+if yoffset and yoffset~=0 then
+ setfield(current,"yoffset",yoffset)
+end
if hascursives then
local cursivex=i.cursivex
if cursivex then
@@ -17344,10 +17204,6 @@ local function inject_everything(head,where)
cursiveanchor=nil
end
end
- local yoffset=i.yoffset
- if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
- end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
insert_node_before(head,current,newkern(leftkern))
@@ -17594,6 +17450,37 @@ function nodes.injections.setspacekerns(font,sequence)
triggers={ [font]=sequence }
end
end
+local getthreshold
+if context then
+ local threshold=1
+ local parameters=fonts.hashes.parameters
+ directives.register("otf.threshold",function(v) threshold=tonumber(v) or 1 end)
+ getthreshold=function(font)
+ local p=parameters[font]
+ local f=p.factor
+ local s=p.spacing
+ local t=threshold*(s and s.width or p.space or 0)-2
+ return t>0 and t or 0,f
+ end
+else
+ injections.threshold=0
+ getthreshold=function(font)
+ local p=fontdata[font].parameters
+ local f=p.factor
+ local s=p.spacing
+ local t=injections.threshold*(s and s.width or p.space or 0)-2
+ return t>0 and t or 0,f
+ end
+end
+injections.getthreshold=getthreshold
+function injections.isspace(n,threshold)
+ if getid(n)==glue_code then
+ local w=getfield(n,"width")
+ if threshold and w>threshold then
+ return 32
+ end
+ end
+end
local function injectspaces(head)
if not triggers then
return head,false
@@ -17609,10 +17496,9 @@ local function injectspaces(head)
local function updatefont(font,trig)
leftkerns=trig.left
rightkerns=trig.right
- local par=fontdata[font].parameters
- factor=par.factor
- threshold=par.spacing.width-1
lastfont=font
+ threshold,
+ factor=getthreshold(font)
end
for n in traverse_id(glue_code,tonut(head)) do
local prev,next=getboth(n)
@@ -17631,7 +17517,7 @@ local function injectspaces(head)
end
end
if prevchar then
- local font=getfont(next)
+ local font=getfont(prev)
local trig=triggers[font]
if trig then
if lastfont~=font then
@@ -17644,7 +17530,7 @@ local function injectspaces(head)
end
if leftkern then
local old=getfield(n,"width")
- if old>=threshold then
+ if old>threshold then
if rightkern then
local new=old+(leftkern+rightkern)*factor
if trace_spaces then
@@ -17663,7 +17549,7 @@ local function injectspaces(head)
leftkern=false
elseif rightkern then
local old=getfield(n,"width")
- if old>=threshold then
+ if old>threshold then
local new=old+rightkern*factor
if trace_spaces then
report_spaces("[%p -> %p] %C",nextchar,old,new)
@@ -18114,11 +18000,7 @@ local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kern
local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end)
local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end)
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
-local quit_on_no_replacement=true
-local zwnjruns=true
local optimizekerns=true
-registerdirective("otf.zwnjruns",function(v) zwnjruns=v end)
-registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement=value end)
local report_direct=logs.reporter("fonts","otf direct")
local report_subchain=logs.reporter("fonts","otf subchain")
local report_chain=logs.reporter("fonts","otf chain")
@@ -18195,6 +18077,7 @@ local getligaindex=injections.getligaindex
local cursonce=true
local fonthashes=fonts.hashes
local fontdata=fonthashes.identifiers
+local fontfeatures=fonthashes.features
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local onetimemessage=fonts.loggers.onetimemessage or function() end
@@ -18214,14 +18097,8 @@ local notmatchpre={}
local notmatchpost={}
local notmatchreplace={}
local handlers={}
-local function isspace(n)
- if getid(n)==glue_code then
- local w=getfield(n,"width")
- if w>=threshold then
- return 32
- end
- end
-end
+local isspace=injections.isspace
+local getthreshold=injections.getthreshold
local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
@@ -18499,7 +18376,7 @@ end
end
return head,base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks)
+local function multiple_glyphs(head,start,multiple,ignoremarks,what)
local nofmultiples=#multiple
if nofmultiples>0 then
resetinjection(start)
@@ -18513,6 +18390,17 @@ local function multiple_glyphs(head,start,multiple,ignoremarks)
insert_node_after(head,start,n)
start=n
end
+ if what==true then
+ elseif what>1 then
+ local m=multiple[nofmultiples]
+ for i=2,what do
+ local n=copy_node(start)
+ resetinjection(n)
+ setchar(n,m)
+ insert_node_after(head,start,n)
+ start=n
+ end
+ end
end
return head,start,true
else
@@ -18583,7 +18471,7 @@ function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1])
+ return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
end
function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
local current=getnext(start)
@@ -19038,7 +18926,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup
if trace_multiples then
logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
end
- return multiple_glyphs(head,start,replacement,sequence.flags[1])
+ return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
end
return head,start,false
end
@@ -19050,7 +18938,7 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku
end
local kind=dataset[4]
local what=dataset[1]
- local value=what==true and tfmdata.shared.features[kind] or what
+ local value=what==true and tfmdata.shared.features[kind] or what
local current=start
while current do
local currentchar=ischar(current)
@@ -19991,16 +19879,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
end
prev=getprev(prev)
- elseif seq[n][32] then
+ elseif seq[n][32] and isspace(prev,threshold) then
n=n-1
prev=getprev(prev)
else
match=false
break
end
- elseif seq[n][32] then
- n=n-1
- prev=getprev(prev)
else
match=false
break
@@ -20114,15 +19999,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
else
end
current=getnext(current)
- elseif seq[n][32] then
+ elseif seq[n][32] and isspace(current,threshold) then
n=n+1
+ current=getnext(current)
else
match=false
break
end
- elseif seq[n][32] then
- n=n+1
- current=getnext(current)
else
match=false
break
@@ -20217,7 +20100,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
if replacements then
head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode)
else
- done=quit_on_no_replacement
+ done=true
if trace_contexts then
logprocess("%s: skipping match",cref(dataset,sequence))
end
@@ -20366,10 +20249,10 @@ local function kernrun(disc,k_run,font,attr,...)
break
end
end
- if prev and (pre or replace) and not ischar(prev,font) then
+ if prev and not ischar(prev,font) then
prev=false
end
- if next and (post or replace) and not ischar(next,font) then
+ if next and not ischar(next,font) then
next=false
end
if pre then
@@ -20795,8 +20678,8 @@ local function featuresprocessor(head,font,attr)
descriptions=tfmdata.descriptions
characters=tfmdata.characters
marks=tfmdata.resources.marks
- factor=tfmdata.parameters.factor
- threshold=tfmdata.parameters.spacing.width or 65536*10
+ threshold,
+ factor=getthreshold(font)
elseif currentfont~=font then
report_warning("nested call with a different font, level %s, quitting",nesting)
nesting=nesting-1
@@ -20824,15 +20707,12 @@ local function featuresprocessor(head,font,attr)
local steps=sequence.steps
local nofsteps=sequence.nofsteps
if not steps then
- local h,d,ok=handler(head,start,dataset,sequence,nil,nil,nil,0,font,attr)
+ local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
if ok then
success=true
if h then
head=h
end
- if d then
- start=d
- end
end
elseif typ=="gsub_reversecontextchain" then
local start=find_node_tail(head)
@@ -21017,9 +20897,25 @@ otf.nodemodeinitializer=featuresinitializer
otf.featuresprocessor=featuresprocessor
otf.handlers=handlers
local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end
-function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
- setspacekerns(font,sequence)
- return head,start,true
+if fontfeatures then
+ function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ local features=fontfeatures[font]
+ local enabled=features.spacekern==true and features.kern==true
+ if enabled then
+ setspacekerns(font,sequence)
+ end
+ return head,start,enabled
+ end
+else
+ function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ local shared=fontdata[font].shared
+ local features=shared and shared.features
+ local enabled=features and features.spacekern==true and features.kern==true
+ if enabled then
+ setspacekerns(font,sequence)
+ end
+ return head,start,enabled
+ end
end
local function hasspacekerns(data)
local sequences=data.resources.sequences
@@ -21053,8 +20949,8 @@ otf.readers.registerextender {
local function spaceinitializer(tfmdata,value)
local resources=tfmdata.resources
local spacekerns=resources and resources.spacekerns
- if spacekerns==nil then
- local properties=tfmdata.properties
+ local properties=tfmdata.properties
+ if value and spacekerns==nil then
if properties and properties.hasspacekerns then
local sequences=resources.sequences
local left={}
@@ -21067,7 +20963,20 @@ local function spaceinitializer(tfmdata,value)
if steps then
local kern=sequence.features.kern
if kern then
- feat=feat or kern
+ if feat then
+ for script,languages in next,kern do
+ local f=feat[k]
+ if f then
+ for l in next,languages do
+ f[l]=true
+ end
+ else
+ feat[script]=languages
+ end
+ end
+ else
+ feat=kern
+ end
for i=1,#steps do
local step=steps[i]
local coverage=step.coverage
@@ -23117,7 +23026,7 @@ if not modules then modules={} end modules ['font-ocl']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local tostring,next=tostring,next
+local tostring,next,format=tostring,next,string.format
local formatters=string.formatters
local otf=fonts.handlers.otf
local f_color_start=formatters["pdf:direct: %f %f %f rg"]
@@ -23234,70 +23143,62 @@ do
end
end
end
-if context and xml.convert then
+do
local report_svg=logs.reporter("fonts","svg conversion")
- local xmlconvert=xml.convert
- local xmlfirst=xml.first
local loaddata=io.loaddata
local savedata=io.savedata
local remove=os.remove
+ if context and xml.convert then
+ local xmlconvert=xml.convert
+ local xmlfirst=xml.first
+ function otfsvg.filterglyph(entry,index)
+ local svg=xmlconvert(entry.data)
+ local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
+ local data=root and tostring(root)
+ return data
+ end
+ else
+ function otfsvg.filterglyph(entry,index)
+ return entry.data
+ end
+ end
function otfsvg.topdf(svgshapes)
- local inkscape=io.popen("inkscape --shell 2>&1","w")
+ local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
local pdfshapes={}
local nofshapes=#svgshapes
local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
local f_convert=formatters["%s --export-pdf=%s\n"]
+ local filterglyph=otfsvg.filterglyph
report_svg("processing %i svg containers",nofshapes)
statistics.starttiming()
for i=1,nofshapes do
local entry=svgshapes[i]
- for j=entry.first,entry.last do
- local svg=xmlconvert(entry.data)
- local root=svg and xmlfirst(svg,"/svg[@id='glyph"..j.."']")
- local data=root and tostring(root)
+ for index=entry.first,entry.last do
+ local data=filterglyph(entry,index)
if data and data~="" then
- local svgfile=f_svgfile(j)
- local pdffile=f_pdffile(j)
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
savedata(svgfile,data)
inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[j]=true
+ pdfshapes[index]=true
end
end
end
inkscape:write("quit\n")
inkscape:close()
report_svg("processing %i pdf results",nofshapes)
- for i in next,pdfshapes do
- local svgfile=f_svgfile(i)
- local pdffile=f_pdffile(i)
- pdfshapes[i]=loaddata(pdffile)
+ for index in next,pdfshapes do
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
+ pdfshapes[index]=loaddata(pdffile)
remove(svgfile)
remove(pdffile)
end
statistics.stoptiming()
- report_svg("conversion time: %0.3f",statistics.elapsedtime())
- return pdfshapes
- end
-else
- function otfsvg.topdf(svgshapes)
- local svgfile="temp-otf-svg-shape.svg"
- local pdffile="temp-otf-svg-shape.pdf"
- local command="inkscape "..svgfile.." --export-pdf="..pdffile
- local pdfshapes={}
- local nofshapes=#svgshapes
- texio.write(formatters["[converting %i svg glyphs to pdf using command %q : "](nofshapes,command))
- for i=1,nofshapes do
- local entry=svgshapes[i]
- for j=entry.first,entry.last do
- texio.write(formatters["%i "](j))
- io.savedata(svgfile,tostring(entry.data))
- os.execute(command)
- pdfshapes[j]=io.loaddata(pdffile)
- end
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds())
end
- os.remove(svgfile)
- texio.write("done]")
return pdfshapes
end
end
@@ -23380,20 +23281,18 @@ if not modules then modules={} end modules ['font-onr']={
license="see context related readme files"
}
local fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers
-local next,type,tonumber,rawget=next,type,tonumber,rawget
+local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset
local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find
local char,byte,sub=string.char,string.byte,string.sub
local abs=math.abs
local bxor,rshift=bit32.bxor,bit32.rshift
-local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg
+local P,S,R,Cmt,C,Ct,Cs,Carg,Cf,Cg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg
local lpegmatch,patterns=lpeg.match,lpeg.patterns
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 report_afm=logs.reporter("fonts","afm loading")
-local report_afm=logs.reporter("fonts","pfb loading")
-fonts=fonts or {}
-local handlers=fonts.handlers or {}
-fonts.handlers=handlers
+local report_pfb=logs.reporter("fonts","pfb loading")
+local handlers=fonts.handlers
local afm=handlers.afm or {}
handlers.afm=afm
local readers=afm.readers or {}
@@ -23415,16 +23314,25 @@ do
end
local initialize=function(str,position,size)
n=0
- m=tonumber(size)
+ m=size
return position+1
end
local charstrings=P("/CharStrings")
+ local encoding=P("/Encoding")
+ local dup=P("dup")
+ local put=P("put")
+ local array=P("array")
local name=P("/")*C((R("az")+R("AZ")+R("09")+S("-_."))^1)
- local size=C(R("09")^1)
+ local digits=R("09")^1
+ local cardinal=digits/tonumber
local spaces=P(" ")^1
+ local spacing=patterns.whitespace^0
local p_filternames=Ct (
- (1-charstrings)^0*charstrings*spaces*Cmt(size,initialize)*(Cmt(name*P(" ")^1*C(R("09")^1),progress)+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,progress)+P(1))^1
)
+ local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
+ Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
+,rawset)
local decrypt
do
local r,c1,c2,n=0,0,0,0
@@ -23457,15 +23365,20 @@ do
end
binary=decrypt(binary,4)
local vector=lpegmatch(p_filternames,binary)
- if vector[1]==".notdef" then
- vector[0]=table.remove(vector,1)
+ for i=1,#vector do
+ vector[i-1]=vector[i]
end
+ vector[#vector]=nil
if not vector then
report_pfb("no vector in %a",filename)
return
end
- return vector
+ local encoding=lpegmatch(p_filterencoding,ascii)
+ return vector,encoding
end
+ local pfb=handlers.pfb or {}
+ handlers.pfb=pfb
+ pfb.loadvector=loadpfbvector
get_indexes=function(data,pfbname)
local vector=loadpfbvector(pfbname)
if vector then
@@ -23691,6 +23604,7 @@ local steps={
"add ligatures",
"add extra kerns",
"normalize features",
+ "check extra features",
"fix names",
}
local function applyenhancers(data,filename)
@@ -23904,6 +23818,7 @@ enhancers["normalize features"]=function(data)
data.resources.features=features
data.resources.sequences=sequences
end
+enhancers["check extra features"]=otf.enhancers.enhance
enhancers["fix names"]=function(data)
for k,v in next,data.descriptions do
local n=v.name
@@ -24265,17 +24180,12 @@ local function read_from_afm(specification)
end
return tfmdata
end
-local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode=lower(value)
- end
-end
registerafmfeature {
name="mode",
description="mode",
initializers={
- base=setmode,
- node=setmode,
+ base=otf.modeinitializer,
+ node=otf.modeinitializer,
}
}
registerafmfeature {
@@ -24290,7 +24200,6 @@ registerafmfeature {
node=otf.featuresprocessor,
}
}
-local check_tfm=readers.check_tfm
fonts.formats.afm="type1"
fonts.formats.pfb="type1"
local function check_afm(specification,fullname)
@@ -24325,7 +24234,8 @@ function readers.afm(specification,method)
tfmdata=check_afm(specification,specification.name.."."..forced)
end
if not tfmdata then
- method=method or definers.method or "afm or tfm"
+ local check_tfm=readers.check_tfm
+ method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm"
if method=="tfm" then
tfmdata=check_tfm(specification,specification.name)
elseif method=="afm" then
@@ -24533,6 +24443,529 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules={} end modules ['font-tfm']={
+ 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 next,type=next,type
+local match,format=string.match,string.format
+local concat,sortedhash=table.concat,table.sortedhash
+local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
+local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end)
+local report_defining=logs.reporter("fonts","defining")
+local report_tfm=logs.reporter("fonts","tfm loading")
+local findbinfile=resolvers.findbinfile
+local setmetatableindex=table.setmetatableindex
+local fonts=fonts
+local handlers=fonts.handlers
+local readers=fonts.readers
+local constructors=fonts.constructors
+local encodings=fonts.encodings
+local tfm=constructors.handlers.tfm
+tfm.version=1.000
+tfm.maxnestingdepth=5
+tfm.maxnestingsize=65536*1024
+local otf=fonts.handlers.otf
+local tfmfeatures=constructors.features.tfm
+local registertfmfeature=tfmfeatures.register
+constructors.resolvevirtualtoo=false
+fonts.formats.tfm="type1"
+fonts.formats.ofm="type1"
+function tfm.setfeatures(tfmdata,features)
+ local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
+ if okay then
+ return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
+ else
+ return {}
+ end
+end
+local depth={}
+local enhancers={}
+local steps={
+ "normalize features",
+ "check extra features"
+}
+enhancers["check extra features"]=otf.enhancers.enhance
+local function applyenhancers(data,filename)
+ for i=1,#steps do
+ local step=steps[i]
+ local enhancer=enhancers[step]
+ if enhancer then
+ if trace_loading then
+ report_tfm("applying enhancer %a",step)
+ end
+ enhancer(data,filename)
+ else
+ report_tfm("invalid enhancer %a",step)
+ end
+ end
+end
+local function read_from_tfm(specification)
+ local filename=specification.filename
+ local size=specification.size
+ depth[filename]=(depth[filename] or 0)+1
+ if trace_defining then
+ report_defining("loading tfm file %a at size %s",filename,size)
+ end
+ local tfmdata=font.read_tfm(filename,size)
+ if tfmdata then
+ local features=specification.features and specification.features.normal or {}
+ local features=constructors.checkedfeatures("tfm",features)
+ specification.features.normal=features
+ local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification)
+ if newtfmdata then
+ tfmdata=newtfmdata
+ end
+ local resources=tfmdata.resources or {}
+ local properties=tfmdata.properties or {}
+ local parameters=tfmdata.parameters or {}
+ local shared=tfmdata.shared or {}
+ shared.features=features
+ shared.resources=resources
+ properties.name=tfmdata.name
+ properties.fontname=tfmdata.fontname
+ properties.psname=tfmdata.psname
+ properties.fullname=tfmdata.fullname
+ properties.filename=specification.filename
+ properties.format=fonts.formats.tfm
+ tfmdata.properties=properties
+ tfmdata.resources=resources
+ tfmdata.parameters=parameters
+ tfmdata.shared=shared
+ shared.rawdata={ resources=resources }
+ shared.features=features
+ if newtfmdata then
+ if not resources.marks then
+ resources.marks={}
+ end
+ if not resources.sequences then
+ resources.sequences={}
+ end
+ if not resources.features then
+ resources.features={
+ gsub={},
+ gpos={},
+ }
+ end
+ if not tfmdata.changed then
+ tfmdata.changed={}
+ end
+ if not tfmdata.descriptions then
+ tfmdata.descriptions=tfmdata.characters
+ end
+ otf.readers.addunicodetable(tfmdata)
+ applyenhancers(tfmdata,filename)
+ constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
+ otf.readers.unifymissing(tfmdata)
+ fonts.mappings.addtounicode(tfmdata,filename)
+ tfmdata.tounicode=1
+ local tounicode=fonts.mappings.tounicode
+ for unicode,v in next,tfmdata.characters do
+ local u=v.unicode
+ if u then
+ v.tounicode=tounicode(u)
+ end
+ end
+ if tfmdata.usedbitmap then
+ tfm.addtounicode(tfmdata)
+ end
+ end
+ shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
+ parameters.factor=1
+ parameters.size=size
+ parameters.slant=parameters.slant or parameters[1] or 0
+ parameters.space=parameters.space or parameters[2] or 0
+ parameters.space_stretch=parameters.space_stretch or parameters[3] or 0
+ parameters.space_shrink=parameters.space_shrink or parameters[4] or 0
+ parameters.x_height=parameters.x_height or parameters[5] or 0
+ parameters.quad=parameters.quad or parameters[6] or 0
+ parameters.extra_space=parameters.extra_space or parameters[7] or 0
+ constructors.enhanceparameters(parameters)
+ if newtfmdata then
+ elseif constructors.resolvevirtualtoo then
+ fonts.loggers.register(tfmdata,file.suffix(filename),specification)
+ local vfname=findbinfile(specification.name,'ovf')
+ if vfname and vfname~="" then
+ local vfdata=font.read_vf(vfname,size)
+ if vfdata then
+ local chars=tfmdata.characters
+ for k,v in next,vfdata.characters do
+ chars[k].commands=v.commands
+ end
+ properties.virtualized=true
+ tfmdata.fonts=vfdata.fonts
+ tfmdata.type="virtual"
+ local fontlist=vfdata.fonts
+ local name=file.nameonly(filename)
+ for i=1,#fontlist do
+ local n=fontlist[i].name
+ local s=fontlist[i].size
+ local d=depth[filename]
+ s=constructors.scaled(s,vfdata.designsize)
+ if d>tfm.maxnestingdepth then
+ report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
+ fontlist[i]={ id=0 }
+ elseif (d>1) and (s>tfm.maxnestingsize) then
+ report_defining("virtual font %a exceeds size %s",n,s)
+ fontlist[i]={ id=0 }
+ else
+ local t,id=fonts.constructors.readanddefine(n,s)
+ fontlist[i]={ id=id }
+ end
+ end
+ end
+ end
+ end
+ properties.haskerns=true
+ properties.hasligatures=true
+ resources.unicodes={}
+ resources.lookuptags={}
+ depth[filename]=depth[filename]-1
+ return tfmdata
+ else
+ depth[filename]=depth[filename]-1
+ end
+end
+local function check_tfm(specification,fullname)
+ local foundname=findbinfile(fullname,'tfm') or ""
+ if foundname=="" then
+ foundname=findbinfile(fullname,'ofm') or ""
+ end
+ if foundname=="" then
+ foundname=fonts.names.getfilename(fullname,"tfm") or ""
+ end
+ if foundname~="" then
+ specification.filename=foundname
+ specification.format="ofm"
+ return read_from_tfm(specification)
+ elseif trace_defining then
+ report_defining("loading tfm with name %a fails",specification.name)
+ end
+end
+readers.check_tfm=check_tfm
+function readers.tfm(specification)
+ local fullname=specification.filename or ""
+ if fullname=="" then
+ local forced=specification.forced or ""
+ if forced~="" then
+ fullname=specification.name.."."..forced
+ else
+ fullname=specification.name
+ end
+ end
+ return check_tfm(specification,fullname)
+end
+readers.ofm=readers.tfm
+do
+ local outfiles={}
+ local tfmcache=table.setmetatableindex(function(t,tfmdata)
+ local id=font.define(tfmdata)
+ t[tfmdata]=id
+ return id
+ end)
+ local encdone=table.setmetatableindex("table")
+ function tfm.reencode(tfmdata,specification)
+ local features=specification.features
+ if not features then
+ return
+ end
+ local features=features.normal
+ if not features then
+ return
+ end
+ local tfmfile=file.basename(tfmdata.name)
+ local encfile=features.reencode
+ local pfbfile=features.pfbfile
+ local bitmap=features.bitmap
+ if not encfile then
+ return
+ end
+ local pfbfile=outfiles[tfmfile]
+ if pfbfile==nil then
+ if bitmap then
+ pfbfile=false
+ elseif type(pfbfile)~="string" then
+ pfbfile=tfmfile
+ end
+ if type(pfbfile)=="string" then
+ pfbfile=file.addsuffix(pfbfile,"pfb")
+ report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile)
+ else
+ report_tfm("using bitmap shapes for %a",tfmfile)
+ pfbfile=false
+ end
+ outfiles[tfmfile]=pfbfile
+ end
+ local encoding=false
+ local vector=false
+ if type(pfbfile)=="string" then
+ local pfb=fonts.constructors.handlers.pfb
+ if pfb and pfb.loadvector then
+ local v,e=pfb.loadvector(pfbfile)
+ if v then
+ vector=v
+ end
+ if e then
+ encoding=e
+ end
+ end
+ end
+ if type(encfile)=="string" and encfile~="auto" then
+ encoding=fonts.encodings.load(file.addsuffix(encfile,"enc"))
+ if encoding then
+ encoding=encoding.vector
+ end
+ end
+ if not encoding then
+ report_tfm("bad encoding for %a, quitting",tfmfile)
+ return
+ end
+ local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes
+ local virtualid=tfmcache[tfmdata]
+ local tfmdata=table.copy(tfmdata)
+ local characters={}
+ local originals=tfmdata.characters
+ local indices={}
+ local parentfont={ "font",1 }
+ local private=fonts.constructors.privateoffset
+ local reported=encdone[tfmfile][encfile]
+ local backmap=vector and table.swapped(vector)
+ local done={}
+ for index,name in sortedhash(encoding) do
+ local unicode=unicoding[name]
+ local original=originals[index]
+ if original then
+ if unicode then
+ original.unicode=unicode
+ else
+ unicode=private
+ private=private+1
+ if not reported then
+ report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode)
+ end
+ end
+ characters[unicode]=original
+ indices[index]=unicode
+ original.name=name
+ if backmap then
+ original.index=backmap[name]
+ else
+ original.commands={ parentfont,{ "char",index } }
+ original.oindex=index
+ end
+ done[name]=true
+ elseif not done[name] then
+ report_tfm("bad index %a in font %a with name %a",index,tfmfile,name)
+ end
+ end
+ encdone[tfmfile][encfile]=true
+ for k,v in next,characters do
+ local kerns=v.kerns
+ if kerns then
+ local t={}
+ for k,v in next,kerns do
+ local i=indices[k]
+ if i then
+ t[i]=v
+ end
+ end
+ v.kerns=next(t) and t or nil
+ end
+ local ligatures=v.ligatures
+ if ligatures then
+ local t={}
+ for k,v in next,ligatures do
+ local i=indices[k]
+ if i then
+ t[i]=v
+ v.char=indices[v.char]
+ end
+ end
+ v.ligatures=next(t) and t or nil
+ end
+ end
+ tfmdata.fonts={ { id=virtualid } }
+ tfmdata.characters=characters
+ tfmdata.fullname=tfmdata.fullname or tfmdata.name
+ tfmdata.psname=file.nameonly(pfbfile or tfmdata.name)
+ tfmdata.filename=pfbfile
+ tfmdata.encodingbytes=2
+ tfmdata.format="type1"
+ tfmdata.tounicode=1
+ tfmdata.embedding="subset"
+ tfmdata.usedbitmap=bitmap and virtualid
+ return tfmdata
+ end
+end
+do
+ local template=[[
+/CIDInit /ProcSet findresource begin
+ 12 dict begin
+ begincmap
+ /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def
+ /CMapName /TeX-bitmap-%s def
+ /CMapType 2 def
+ 1 begincodespacerange
+ <00> <FF>
+ endcodespacerange
+ %s beginbfchar
+%s
+ endbfchar
+ endcmap
+CMapName currentdict /CMap defineresource pop end
+end
+end
+]]
+ local flushstreamobject=lpdf and lpdf.flushstreamobject
+ local setfontattributes=pdf.setfontattributes
+ if not flushstreamobject then
+ flushstreamobject=function(data)
+ return pdf.obj {
+ immediate=true,
+ type="stream",
+ string=data,
+ }
+ end
+ end
+ if not setfontattributes then
+ setfontattributes=function(id,data)
+ print(format("your luatex is too old so no tounicode bitmap font%i",id))
+ end
+ end
+ function tfm.addtounicode(tfmdata)
+ local id=tfmdata.usedbitmap
+ local map={}
+ local char={}
+ for k,v in next,tfmdata.characters do
+ local index=v.oindex
+ local tounicode=v.tounicode
+ if index and tounicode then
+ map[index]=tounicode
+ end
+ end
+ for k,v in sortedhash(map) do
+ char[#char+1]=format("<%02X> <%s>",k,v)
+ end
+ char=concat(char,"\n")
+ local stream=format(template,id,id,#char,char)
+ local reference=flushstreamobject(stream,nil,true)
+ setfontattributes(id,format("/ToUnicode %i 0 R",reference))
+ end
+end
+do
+ local everywhere={ ["*"]={ ["*"]=true } }
+ local noflags={ false,false,false,false }
+ enhancers["normalize features"]=function(data)
+ local ligatures=setmetatableindex("table")
+ local kerns=setmetatableindex("table")
+ local characters=data.characters
+ for u,c in next,characters do
+ local l=c.ligatures
+ local k=c.kerns
+ if l then
+ ligatures[u]=l
+ for u,v in next,l do
+ l[u]={ ligature=v.char }
+ end
+ c.ligatures=nil
+ end
+ if k then
+ kerns[u]=k
+ for u,v in next,k do
+ k[u]=v
+ end
+ c.kerns=nil
+ end
+ end
+ for u,l in next,ligatures do
+ for k,v in next,l do
+ local vl=v.ligature
+ local dl=ligatures[vl]
+ if dl then
+ for kk,vv in next,dl do
+ v[kk]=vv
+ end
+ end
+ end
+ end
+ local features={
+ gpos={},
+ gsub={},
+ }
+ local sequences={
+ }
+ if next(ligatures) then
+ features.gsub.liga=everywhere
+ data.properties.hasligatures=true
+ sequences[#sequences+1]={
+ features={
+ liga=everywhere,
+ },
+ flags=noflags,
+ name="s_s_0",
+ nofsteps=1,
+ order={ "liga" },
+ type="gsub_ligature",
+ steps={
+ {
+ coverage=ligatures,
+ },
+ },
+ }
+ end
+ if next(kerns) then
+ features.gpos.kern=everywhere
+ data.properties.haskerns=true
+ sequences[#sequences+1]={
+ features={
+ kern=everywhere,
+ },
+ flags=noflags,
+ name="p_s_0",
+ nofsteps=1,
+ order={ "kern" },
+ type="gpos_pair",
+ steps={
+ {
+ format="kern",
+ coverage=kerns,
+ },
+ },
+ }
+ end
+ data.resources.features=features
+ data.resources.sequences=sequences
+ data.shared.resources=data.shared.resources or resources
+ end
+end
+registertfmfeature {
+ name="mode",
+ description="mode",
+ initializers={
+ base=otf.modeinitializer,
+ node=otf.modeinitializer,
+ }
+}
+registertfmfeature {
+ name="features",
+ description="features",
+ default=true,
+ initializers={
+ base=otf.basemodeinitializer,
+ node=otf.nodemodeinitializer,
+ },
+ processors={
+ node=otf.featuresprocessor,
+ }
+}
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules={} end modules ['font-lua']={
version=1.001,
comment="companion to font-ini.mkiv",
@@ -24582,10 +25015,11 @@ if not modules then modules={} end modules ['font-def']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub
+local lower,gsub=string.lower,string.gsub
local tostring,next=tostring,next
local lpegmatch=lpeg.match
local suffixonly,removesuffix=file.suffix,file.removesuffix
+local formatters=string.formatters
local allocate=utilities.storage.allocate
local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end)
@@ -24746,7 +25180,7 @@ function definers.applypostprocessors(tfmdata)
local extrahash=postprocessors[i](tfmdata)
if type(extrahash)=="string" and extrahash~="" then
extrahash=gsub(lower(extrahash),"[^a-z]","-")
- properties.fullname=format("%s-%s",properties.fullname,extrahash)
+ properties.fullname=formatters["%s-%s"](properties.fullname,extrahash)
end
end
end
diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua
index b6e889e..786f619 100644
--- a/src/luaotfload-features.lua
+++ b/src/luaotfload-features.lua
@@ -1334,14 +1334,73 @@ local noflags = { false, false, false, false }
local tohash = table.tohash
-local function current_addfeature(data,feature,specifications)
+local function validspecification(specification,name)
+ local dataset = specification.dataset
+ if dataset then
+ -- okay
+ elseif specification[1] then
+ dataset = specification
+ specification = { dataset = dataset }
+ else
+ dataset = { { data = specification.data } }
+ specification.data = nil
+ specification.dataset = dataset
+ end
+ local first = dataset[1]
+ if first then
+ first = first.data
+ end
+ if not first then
+ report_otf("invalid feature specification, no dataset")
+ return
+ end
+ if type(name) ~= "string" then
+ name = specification.name or first.name
+ end
+ if type(name) ~= "string" then
+ report_otf("invalid feature specification, no name")
+ return
+ end
+ local n = #dataset
+ if n > 0 then
+ for i=1,n do
+ setmetatableindex(dataset[i],specification)
+ end
+ return specification, name
+ end
+end
+
+local function addfeature(data,feature,specifications)
+
+ -- todo: add some validator / check code so that we're more tolerant to
+ -- user errors
+
+ if not specifications then
+ report_otf("missing specification")
+ return
+ end
+
local descriptions = data.descriptions
local resources = data.resources
local features = resources.features
local sequences = resources.sequences
+
if not features or not sequences then
+ report_otf("missing specification")
return
end
+
+ local alreadydone = resources.alreadydone
+ if not alreadydone then
+ alreadydone = { }
+ resources.alreadydone = alreadydone
+ end
+ if alreadydone[specifications] then
+ return
+ else
+ alreadydone[specifications] = true
+ end
+
-- feature has to be unique but the name entry wins eventually
local fontfeatures = resources.features or everywhere
@@ -1351,9 +1410,10 @@ local function current_addfeature(data,feature,specifications)
local skip = 0
local aglunicodes = false
- if not specifications[1] then
- -- so we accept a one entry specification
- specifications = { specifications }
+ local specifications = validspecification(specifications,feature)
+ if not specifications then
+ -- report_otf("invalid specification")
+ return
end
local function tounicode(code)
@@ -1655,11 +1715,15 @@ local function current_addfeature(data,feature,specifications)
return coverage
end
- for s=1,#specifications do
- local specification = specifications[s]
- local valid = specification.valid
- local feature = specification.name or feature
- if not valid or valid(data,specification,feature) then
+ local dataset = specifications.dataset
+
+ for s=1,#dataset do
+ local specification = dataset[s]
+ local valid = specification.valid -- nowhere used
+ local feature = specification.name or feature
+ if not feature or feature == "" then
+ report_otf("no valid name given for extra feature")
+ elseif not valid or valid(data,specification,feature) then -- anum uses this
local initialize = specification.initialize
if initialize then
-- when false is returned we initialize only once
@@ -1776,10 +1840,37 @@ local function current_addfeature(data,feature,specifications)
type = types[featuretype],
}
-- todo : before|after|index
- if specification.prepend then
- insert(sequences,1,sequence)
- else
+ local prepend = specification.prepend
+ if prepend == true then
+ prepend = 1
+ end
+ if type(prepend) == "number" then
+ -- okay
+ elseif type(prepend) == "string" then
+ local index = false
+ for i=1,#sequences do
+ local s = sequences[i]
+ local f = s.features
+ if f then
+ for k in next, f do
+ if k == prepend then
+ index = i
+ break
+ end
+ end
+ if index then
+ break
+ end
+ end
+ end
+ prepend = index
+ elseif prepend == true then
+ prepend = 1
+ end
+ if not prepend or prepend <= 0 or prepend > #sequences then
insert(sequences,sequence)
+ else
+ insert(sequences,prepend,sequence)
end
-- register in metadata (merge as there can be a few)
local features = fontfeatures[category]
@@ -1953,12 +2044,17 @@ function add_otf_feature (name, specification)
specification = name
name = specification.name
end
- if type (name) == "string" then
+ if type (specification) ~= "table" then
+ logreport ("both", 0, "features",
+ "invalid feature specification ā€œ%sā€", tostring (name))
+ return
+ end
+ if name and specification then
extrafeatures[name] = specification
end
end
-otf.addfeature = add_otf_feature
+otf.addfeature = add_otf_feature
local install_extra_features = function (data, filename, raw)
local metadata = data and data.metadata
@@ -2002,7 +2098,7 @@ return {
end
otf = fonts.handlers.otf
- otf.enhancers.addfeature = current_addfeature
+ otf.enhancers.addfeature = addfeature
otf.enhancers.register ("check extra features",
install_extra_features)
diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua
index c977b49..25558be 100644
--- a/src/luaotfload-init.lua
+++ b/src/luaotfload-init.lua
@@ -251,7 +251,6 @@ local context_modules = {
{ ctx, "font-cid" },
{ ctx, "font-map" },
{ ltx, "luatex-fonts-syn" },
- { ctx, "font-tfm" },
{ ctx, "font-oti" },
{ ctx, "font-otr" },
{ ctx, "font-cff" },
@@ -268,6 +267,7 @@ local context_modules = {
{ ctx, "font-onr" },
{ ctx, "font-one" },
{ ctx, "font-afk" },
+ { ctx, "font-tfm" },
{ ctx, "font-lua" },
{ ctx, "font-def" },
{ ltx, "luatex-fonts-ext" },
@@ -531,7 +531,6 @@ local init_main = function ()
load_fontloader_module "font-cid"
load_fontloader_module "font-map"
load_fontloader_module "fonts-syn"
- load_fontloader_module "font-tfm"
load_fontloader_module "font-oti"
load_fontloader_module "font-otr"
load_fontloader_module "font-cff"
@@ -548,6 +547,7 @@ local init_main = function ()
load_fontloader_module "font-onr"
load_fontloader_module "font-one"
load_fontloader_module "font-afk"
+ load_fontloader_module "font-tfm"
load_fontloader_module "font-lua"
load_fontloader_module "font-def"
load_fontloader_module "fonts-ext"
diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua
index 68cc50f..b544cf1 100644
--- a/src/luaotfload-loaders.lua
+++ b/src/luaotfload-loaders.lua
@@ -55,7 +55,7 @@ local afm_loader = function (specification)
specification.forced = "afm"
specification.sub = false
specification.forcedname = file.addsuffix(specification.name, "afm")
- inspect(specification)
+--inspect(specification)
return afm_reader (specification, "afm")
end
@@ -98,6 +98,7 @@ local install_formats = function ()
and aux ("lua", lua_reader)
and aux ("pfa", unsupported_reader "pfa")
and aux ("afm", afm_loader)
+ and aux ("tfm", afm_loader)
and aux ("pfb", afm_compat_message) --- pfb loader is incomplete
and aux ("ofm", readers.tfm)
and aux ("dfont", unsupported_reader "dfont")
diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua
index bc9e425..fee5980 100755
--- a/src/luaotfload-tool.lua
+++ b/src/luaotfload-tool.lua
@@ -8,7 +8,7 @@
-----------------------------------------------------------------------
luaotfload = luaotfload or { }
-local version = "2.7"
+local version = "2.8"
luaotfload.version = version
luaotfload.min_luatex_version = { 0, 95, 0 } --- i. e. 0.95.0
luaotfload.self = "luaotfload-tool"
@@ -138,13 +138,14 @@ require "fontloader-basics-gen.lua"
texio.write, texio.write_nl = backup.write, backup.write_nl
utilities = backup.utilities
+pdf = pdf or { } --- for font-tfm
+
require "fontloader-data-con"
require "fontloader-font-ini"
require "fontloader-font-con"
require "fontloader-fonts-enc"
require "fontloader-font-cid"
require "fontloader-font-map"
-require "fontloader-font-tfm"
require "fontloader-font-oti"
require "fontloader-font-otr"
require "fontloader-font-cff"
@@ -160,6 +161,7 @@ require "fontloader-font-oto"
require "fontloader-font-onr"
require "fontloader-font-one"
require "fontloader-font-afk"
+require "fontloader-font-tfm"
require "fontloader-font-lua"
require "fontloader-font-def"
require "fontloader-fonts-ext"