summaryrefslogtreecommitdiff
path: root/src/fontloader/misc
diff options
context:
space:
mode:
authorPhilipp Gesang <phg@phi-gamma.net>2016-06-15 00:02:42 +0200
committerGitHub <noreply@github.com>2016-06-15 00:02:42 +0200
commit36cc5c9c567e24916f254203fc362bf124e26d02 (patch)
tree56cdd0a401ffbb99e8702f47a7865677b0971a8e /src/fontloader/misc
parent17fbf1d1c26047f1e0e80fc6e5f3331f6183a795 (diff)
parentba744a4bce3ed03eefbf2b4746fa24e6d388d9ff (diff)
downloadluaotfload-36cc5c9c567e24916f254203fc362bf124e26d02.tar.gz
Merge pull request #364 from phi-gamma/master
fixes, 3rd edition
Diffstat (limited to 'src/fontloader/misc')
-rw-r--r--src/fontloader/misc/fontloader-font-con.lua90
-rw-r--r--src/fontloader/misc/fontloader-font-dsp.lua241
-rw-r--r--src/fontloader/misc/fontloader-font-gbn.lua21
-rw-r--r--src/fontloader/misc/fontloader-font-ini.lua2
-rw-r--r--src/fontloader/misc/fontloader-font-map.lua233
-rw-r--r--src/fontloader/misc/fontloader-font-ocl.lua297
-rw-r--r--src/fontloader/misc/fontloader-font-one.lua (renamed from src/fontloader/misc/fontloader-font-afm.lua)813
-rw-r--r--src/fontloader/misc/fontloader-font-onr.lua411
-rw-r--r--src/fontloader/misc/fontloader-font-osd.lua5
-rw-r--r--src/fontloader/misc/fontloader-font-ota.lua3
-rw-r--r--src/fontloader/misc/fontloader-font-otd.lua51
-rw-r--r--src/fontloader/misc/fontloader-font-oti.lua4
-rw-r--r--src/fontloader/misc/fontloader-font-otj.lua45
-rw-r--r--src/fontloader/misc/fontloader-font-otl.lua36
-rw-r--r--src/fontloader/misc/fontloader-font-oto.lua4
-rw-r--r--src/fontloader/misc/fontloader-font-otr.lua43
-rw-r--r--src/fontloader/misc/fontloader-font-ots.lua47
-rw-r--r--src/fontloader/misc/fontloader-font-oup.lua59
-rw-r--r--src/fontloader/misc/fontloader-font-tfm.lua6
-rw-r--r--src/fontloader/misc/fontloader-fonts-ext.lua2
-rw-r--r--src/fontloader/misc/fontloader-fonts.lua10
-rw-r--r--src/fontloader/misc/fontloader-math.tex12
22 files changed, 1566 insertions, 869 deletions
diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua
index b118535..1a0daff 100644
--- a/src/fontloader/misc/fontloader-font-con.lua
+++ b/src/fontloader/misc/fontloader-font-con.lua
@@ -10,7 +10,6 @@ if not modules then modules = { } end modules ['font-con'] = {
local next, tostring, rawget = next, tostring, rawget
local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub
-local utfbyte = utf.byte
local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
local derivetable = table.derive
@@ -338,6 +337,20 @@ function constructors.enhanceparameters(parameters)
}
end
+local function mathkerns(v,vdelta)
+ local k = { }
+ for i=1,#v do
+ local entry = v[i]
+ local height = entry.height
+ local kern = entry.kern
+ k[i] = {
+ height = height and vdelta*height or 0,
+ kern = kern and vdelta*kern or 0,
+ }
+ end
+ return k
+end
+
function constructors.scale(tfmdata,specification)
local target = { } -- the new table
--
@@ -749,22 +762,15 @@ function constructors.scale(tfmdata,specification)
chr.top_accent = vdelta*va
end
if stackmath then
- local mk = character.mathkerns -- not in math ?
+ local mk = character.mathkerns
if mk then
- local kerns = { }
- local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.top_right = k end
- local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.top_left = k end
- local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.bottom_left = k end
- local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.bottom_right = k end
- chr.mathkern = kerns -- singular -> should be patched in luatex !
+ local tr, tl, br, bl = mk.topright, mk.topleft, mk.bottomright, mk.bottomleft
+ chr.mathkern = { -- singular -> should be patched in luatex !
+ top_right = tr and mathkerns(tr,vdelta) or nil,
+ top_left = tl and mathkerns(tl,vdelta) or nil,
+ bottom_right = br and mathkerns(br,vdelta) or nil,
+ bottom_left = bl and mathkerns(bl,vdelta) or nil,
+ }
end
end
if hasitalics then
@@ -1043,6 +1049,29 @@ function constructors.hashfeatures(specification) -- will be overloaded
return "unknown"
end
+-- hashmethods.normal = function(list)
+-- local s = { }
+-- local n = 0
+-- for k, v in next, list do
+-- if not k then
+-- -- no need to add to hash
+-- elseif k == "number" or k == "features" then
+-- -- no need to add to hash (maybe we need a skip list)
+-- else
+-- n = n + 1
+-- s[n] = k
+-- end
+-- end
+-- if n > 0 then
+-- sort(s)
+-- for i=1,n do
+-- local k = s[i]
+-- s[i] = k .. '=' .. tostring(list[k])
+-- end
+-- return concat(s,"+")
+-- end
+-- end
+
hashmethods.normal = function(list)
local s = { }
local n = 0
@@ -1053,15 +1082,11 @@ hashmethods.normal = function(list)
-- no need to add to hash (maybe we need a skip list)
else
n = n + 1
- s[n] = k
+ s[n] = k .. '=' .. tostring(v)
end
end
if n > 0 then
sort(s)
- for i=1,n do
- local k = s[i]
- s[i] = k .. '=' .. tostring(list[k])
- end
return concat(s,"+")
end
end
@@ -1230,7 +1255,11 @@ function constructors.getfeatureaction(what,where,mode,name)
end
end
-function constructors.newhandler(what) -- could be a metatable newindex
+local newhandler = { }
+constructors.handlers = newhandler -- downward compatible
+constructors.newhandler = newhandler
+
+local function setnewhandler(what) -- could be a metatable newindex
local handler = handlers[what]
if not handler then
handler = { }
@@ -1239,7 +1268,16 @@ function constructors.newhandler(what) -- could be a metatable newindex
return handler
end
-function constructors.newfeatures(what) -- could be a metatable newindex
+setmetatable(newhandler, {
+ __call = function(t,k) local v = t[k] return v end,
+ __index = function(t,k) local v = setnewhandler(k) t[k] = v return v end,
+})
+
+local newfeatures = { }
+constructors.newfeatures = newfeatures -- downward compatible
+constructors.features = newfeatures
+
+local function setnewfeatures(what)
local handler = handlers[what]
local features = handler.features
if not features then
@@ -1259,6 +1297,11 @@ function constructors.newfeatures(what) -- could be a metatable newindex
return features
end
+setmetatable(newfeatures, {
+ __call = function(t,k) local v = t[k] return v end,
+ __index = function(t,k) local v = setnewfeatures(k) t[k] = v return v end,
+})
+
--[[ldx--
<p>We need to check for default features. For this we provide
a helper function.</p>
@@ -1286,7 +1329,6 @@ function constructors.initializefeatures(what,tfmdata,features,trace,report)
local properties = tfmdata.properties or { } -- brrr
local whathandler = handlers[what]
local whatfeatures = whathandler.features
- local whatinitializers = whatfeatures.initializers
local whatmodechecker = whatfeatures.modechecker
-- properties.mode can be enforces (for instance in font-otd)
local mode = properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base"
diff --git a/src/fontloader/misc/fontloader-font-dsp.lua b/src/fontloader/misc/fontloader-font-dsp.lua
index 330a940..a1ae17f 100644
--- a/src/fontloader/misc/fontloader-font-dsp.lua
+++ b/src/fontloader/misc/fontloader-font-dsp.lua
@@ -69,7 +69,6 @@ local readers = fonts.handlers.otf.readers
local streamreader = readers.streamreader
local setposition = streamreader.setposition
-local skipbytes = streamreader.skip
local skipshort = streamreader.skipshort
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
@@ -77,6 +76,7 @@ local readshort = streamreader.readinteger2 -- 16-bit signed integer
local readfword = readshort
local readstring = streamreader.readstring
local readtag = streamreader.readtag
+local readbytes = streamreader.readbytes
local gsubhandlers = { }
local gposhandlers = { }
@@ -716,6 +716,8 @@ function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
end
end
+-- we see coverage format 0x300 in some old ms fonts
+
local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
@@ -1599,6 +1601,14 @@ do
local reported = { }
+ local function report_issue(i,what,sequence,kind)
+ local name = sequence.name
+ if not reported[name] then
+ report("rule %i in %s lookup %a has %s lookups",i,what,name,kind)
+ reported[name] = true
+ end
+ end
+
for i=lastsequence+1,nofsequences do
local sequence = sequences[i]
local steps = sequence.steps
@@ -1610,18 +1620,10 @@ do
local rule = rules[i]
local rlookups = rule.lookups
if not rlookups then
- local name = sequence.name
- if not reported[name] then
- report("rule %i in %s lookup %a has %s lookups",i,what,name,"no")
- reported[name] = true
- end
+ report_issue(i,what,sequence,"no")
elseif not next(rlookups) then
- local name = sequence.name
- if not reported[name] then
- -- can be ok as it aborts a chain sequence
- report("rule %i in %s lookup %a has %s lookups",i,what,name,"empty")
- reported[name] = true
- end
+ -- can be ok as it aborts a chain sequence
+ report_issue(i,what,sequence,"empty")
rule.lookups = nil
else
for index, lookupid in sortedhash(rlookups) do -- nicer
@@ -1629,23 +1631,36 @@ do
if not h then
-- here we have a lookup that is used independent as well
-- as in another one
- nofsublookups = nofsublookups + 1
- -- report("registering %i as sublookup %i",lookupid,nofsublookups)
- local d = lookups[lookupid].done
- h = {
- index = nofsublookups, -- handy for tracing
- name = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
- derived = true, -- handy for tracing
- steps = d.steps,
- nofsteps = d.nofsteps,
- type = d.lookuptype,
- markclass = d.markclass or nil,
- flags = d.flags,
- -- chain = d.chain,
- }
- sublookuplist[nofsublookups] = h
- sublookuphash[lookupid] = nofsublookups
- sublookupcheck[lookupid] = 1
+ local lookup = lookups[lookupid]
+ if lookup then
+ local d = lookup.done
+ if d then
+ nofsublookups = nofsublookups + 1
+ -- report("registering %i as sublookup %i",lookupid,nofsublookups)
+ h = {
+ index = nofsublookups, -- handy for tracing
+ name = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
+ derived = true, -- handy for tracing
+ steps = d.steps,
+ nofsteps = d.nofsteps,
+ type = d.lookuptype,
+ markclass = d.markclass or nil,
+ flags = d.flags,
+ -- chain = d.chain,
+ }
+ sublookuplist[nofsublookups] = h
+ sublookuphash[lookupid] = nofsublookups
+ sublookupcheck[lookupid] = 1
+ else
+ report_issue(i,what,sequence,"missing")
+ rule.lookups = nil
+ break
+ end
+ else
+ report_issue(i,what,sequence,"bad")
+ rule.lookups = nil
+ break
+ end
else
sublookupcheck[lookupid] = sublookupcheck[lookupid] + 1
end
@@ -2015,16 +2030,15 @@ local function readmathglyphinfo(f,fontdata,offset)
local function get(offset)
setposition(f,kernoffset+offset)
local n = readushort(f)
- if n > 0 then
+ if n == 0 then
+ local k = readmathvalue(f)
+ if k == 0 then
+ -- no need for it (happens sometimes)
+ else
+ return { { kern = k } }
+ end
+ else
local l = { }
- -- for i=1,n do
- -- l[i] = { readushort(f), 0 } -- height, kern
- -- skipshort(f)
- -- end
- -- for i=1,n do
- -- l[i][2] = readushort(f)
- -- skipshort(f)
- -- end
for i=1,n do
l[i] = { height = readmathvalue(f) }
end
@@ -2059,10 +2073,10 @@ local function readmathglyphinfo(f,fontdata,offset)
if next(kernset) then
local glyph = glyphs[coverage[i]]
local math = glyph.math
- if not math then
- glyph.math = { kerns = kernset }
- else
+ if math then
math.kerns = kernset
+ else
+ glyph.math = { kerns = kernset }
end
end
end
@@ -2178,7 +2192,7 @@ function readers.math(f,fontdata,specification)
setposition(f,tableoffset)
local version = readulong(f)
if version ~= 0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,what,fontdata.filename)
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
return
end
local constants = readushort(f)
@@ -2198,3 +2212,146 @@ function readers.math(f,fontdata,specification)
end
end
end
+
+function readers.colr(f,fontdata,specification)
+ local datatable = fontdata.tables.colr
+ if datatable then
+ if specification.glyphs then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ local version = readushort(f)
+ if version ~= 0 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
+ return
+ end
+ if not fontdata.tables.cpal then
+ report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
+ fontdata.colorpalettes = { }
+ end
+ local glyphs = fontdata.glyphs
+ local nofglyphs = readushort(f)
+ local baseoffset = readulong(f)
+ local layeroffset = readulong(f)
+ local noflayers = readushort(f)
+ local layerrecords = { }
+ local maxclass = 0
+ -- The special value 0xFFFF is foreground (but we index from 1). It
+ -- more looks like indices into a palette so 'class' is a better name
+ -- than 'palette'.
+ setposition(f,tableoffset + layeroffset)
+ for i=1,noflayers do
+ local slot = readushort(f)
+ local class = readushort(f)
+ if class < 0xFFFF then
+ class = class + 1
+ if class > maxclass then
+ maxclass = class
+ end
+ end
+ layerrecords[i] = {
+ slot = slot,
+ class = class,
+ }
+ end
+ fontdata.maxcolorclass = maxclass
+ setposition(f,tableoffset + baseoffset)
+ for i=0,nofglyphs-1 do
+ local glyphindex = readushort(f)
+ local firstlayer = readushort(f)
+ local noflayers = readushort(f)
+ local t = { }
+ for i=1,noflayers do
+ t[i] = layerrecords[firstlayer+i]
+ end
+ glyphs[glyphindex].colors = t
+ end
+ end
+ fontdata.hascolor = true
+ end
+end
+
+function readers.cpal(f,fontdata,specification)
+ if specification.glyphs then
+ local datatable = fontdata.tables.cpal
+ if datatable then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ local version = readushort(f)
+ if version > 1 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
+ return
+ end
+ local nofpaletteentries = readushort(f)
+ local nofpalettes = readushort(f)
+ local nofcolorrecords = readushort(f)
+ local firstcoloroffset = readulong(f)
+ local colorrecords = { }
+ local palettes = { }
+ for i=1,nofpalettes do
+ palettes[i] = readushort(f)
+ end
+ if version == 1 then
+ -- used for guis
+ local palettettypesoffset = readulong(f)
+ local palettelabelsoffset = readulong(f)
+ local paletteentryoffset = readulong(f)
+ end
+ setposition(f,tableoffset+firstcoloroffset)
+ for i=1,nofcolorrecords do
+ local b, g, r, a = readbytes(f,4)
+ colorrecords[i] = {
+ r, g, b, a ~= 255 and a or nil,
+ }
+ end
+ for i=1,nofpalettes do
+ local p = { }
+ local o = palettes[i]
+ for j=1,nofpaletteentries do
+ p[j] = colorrecords[o+j]
+ end
+ palettes[i] = p
+ end
+ fontdata.colorpalettes = palettes
+ end
+ end
+end
+
+function readers.svg(f,fontdata,specification)
+ local datatable = fontdata.tables.svg
+ if datatable then
+ if specification.glyphs then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ local version = readushort(f)
+ if version ~= 0 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
+ return
+ end
+ local glyphs = fontdata.glyphs
+ local indexoffset = tableoffset + readulong(f)
+ local reserved = readulong(f)
+ setposition(f,indexoffset)
+ local nofentries = readushort(f)
+ local entries = { }
+ for i=1,nofentries do
+ entries[i] = {
+ first = readushort(f),
+ last = readushort(f),
+ offset = indexoffset + readulong(f),
+ length = readulong(f),
+ }
+ end
+ for i=1,nofentries do
+ local entry = entries[i]
+ setposition(f,entry.offset)
+ entries[i] = {
+ first = entry.first,
+ last = entry.last,
+ data = readstring(f,entry.length)
+ }
+ end
+ fontdata.svgshapes = entries
+ end
+ fontdata.hascolor = true
+ end
+end
diff --git a/src/fontloader/misc/fontloader-font-gbn.lua b/src/fontloader/misc/fontloader-font-gbn.lua
index daa072b..1ae817d 100644
--- a/src/fontloader/misc/fontloader-font-gbn.lua
+++ b/src/fontloader/misc/fontloader-font-gbn.lua
@@ -19,7 +19,6 @@ local nodes = nodes
local nuts = nodes.nuts -- context abstraction of direct nodes
local traverse_id = nuts.traverse_id
-local remove_node = nuts.remove
local free_node = nuts.free
local glyph_code = nodes.nodecodes.glyph
@@ -126,17 +125,19 @@ function nodes.handlers.nodepass(head)
local variant = hash[getchar(p)]
if variant then
setchar(p,variant)
- if not redundant then
- redundant = { n }
- else
- redundant[#redundant+1] = n
- end
end
end
end
+ -- per generic user request we always remove selectors
+ if not redundant then
+ redundant = { n }
+ else
+ redundant[#redundant+1] = n
+ end
end
end
end
+ local nofbasefonts = #basefonts
if redundant then
for i=1,#redundant do
local r = redundant[i]
@@ -147,8 +148,8 @@ function nodes.handlers.nodepass(head)
else
setlink(p,n)
end
- if b > 0 then
- for i=1,b do
+ if nofbasefonts > 0 then
+ for i=1,nofbasefonts do
local bi = basefonts[i]
if r == bi[1] then
bi[1] = n
@@ -192,8 +193,8 @@ function nodes.handlers.nodepass(head)
end
end
end
- if basemodepass and #basefonts > 0 then
- for i=1,#basefonts do
+ if basemodepass and nofbasefonts > 0 then
+ for i=1,nofbasefonts do
local range = basefonts[i]
local start = range[1]
local stop = range[2]
diff --git a/src/fontloader/misc/fontloader-font-ini.lua b/src/fontloader/misc/fontloader-font-ini.lua
index c547f89..abc3194 100644
--- a/src/fontloader/misc/fontloader-font-ini.lua
+++ b/src/fontloader/misc/fontloader-font-ini.lua
@@ -12,8 +12,6 @@ if not modules then modules = { } end modules ['font-ini'] = {
local allocate = utilities.storage.allocate
-local report_defining = logs.reporter("fonts","defining")
-
fonts = fonts or { }
local fonts = fonts
diff --git a/src/fontloader/misc/fontloader-font-map.lua b/src/fontloader/misc/fontloader-font-map.lua
index 509e751..6151b37 100644
--- a/src/fontloader/misc/fontloader-font-map.lua
+++ b/src/fontloader/misc/fontloader-font-map.lua
@@ -10,7 +10,6 @@ local tonumber, next, type = tonumber, next, type
local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match
-local utfbyte = utf.byte
local floor = math.floor
local formatters = string.formatters
@@ -45,7 +44,7 @@ of obsolete. Some code may move to runtime or auxiliary modules.</p>
-- end
-- end
-local hex = R("AF","09")
+local hex = R("AF","af","09")
----- hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end
----- hexsix = (hex*hex*hex*hex*hex*hex) / function(s) return tonumber(s,16) end
local hexfour = (hex*hex*hex^-2) / function(s) return tonumber(s,16) end
@@ -140,7 +139,7 @@ local f_double = formatters["%04X%04X"]
-- end
-- end
-local function tounicode16(unicode,name)
+local function tounicode16(unicode)
if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then
return f_single(unicode)
else
@@ -149,7 +148,7 @@ local function tounicode16(unicode,name)
end
end
-local function tounicode16sequence(unicodes,name)
+local function tounicode16sequence(unicodes)
local t = { }
for l=1,#unicodes do
local u = unicodes[l]
@@ -295,145 +294,145 @@ function mappings.addtounicode(data,filename,checklookups)
local ns = 0
local nl = 0
--
- for unic, glyph in next, descriptions do
+ for du, glyph in next, descriptions do
local name = glyph.name
if name then
- local index = glyph.index
- local r = overloads[name]
- if r then
+ local overload = overloads[name]
+ if overload then
-- get rid of weird ligatures
- -- glyph.name = r.name
- glyph.unicode = r.unicode
- elseif not unic or unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
- local unicode = unicodevector[name] or contextvector[name]
- if unicode then
- glyph.unicode = unicode
- ns = ns + 1
- end
- -- cidmap heuristics, beware, there is no guarantee for a match unless
- -- the chain resolves
- if (not unicode) and usedmap then
- local foundindex = lpegmatch(oparser,name)
- if foundindex then
- unicode = cidcodes[foundindex] -- name to number
- if unicode then
- glyph.unicode = unicode
- ns = ns + 1
- else
- local reference = cidnames[foundindex] -- number to name
- if reference then
- local foundindex = lpegmatch(oparser,reference)
- if foundindex then
- unicode = cidcodes[foundindex]
- if unicode then
- glyph.unicode = unicode
- ns = ns + 1
+ -- glyph.name = overload.name
+ glyph.unicode = overload.unicode
+ else
+ local gu = glyph.unicode -- can already be set (number or table)
+ if not gu or gu == -1 or du >= private or (du >= 0xE000 and du <= 0xF8FF) or du == 0xFFFE or du == 0xFFFF then
+ local unicode = unicodevector[name] or contextvector[name]
+ if unicode then
+ glyph.unicode = unicode
+ ns = ns + 1
+ end
+ -- cidmap heuristics, beware, there is no guarantee for a match unless
+ -- the chain resolves
+ if (not unicode) and usedmap then
+ local foundindex = lpegmatch(oparser,name)
+ if foundindex then
+ unicode = cidcodes[foundindex] -- name to number
+ if unicode then
+ glyph.unicode = unicode
+ ns = ns + 1
+ else
+ local reference = cidnames[foundindex] -- number to name
+ if reference then
+ local foundindex = lpegmatch(oparser,reference)
+ if foundindex then
+ unicode = cidcodes[foundindex]
+ if unicode then
+ glyph.unicode = unicode
+ ns = ns + 1
+ end
end
- end
- if not unicode or unicode == "" then
- local foundcodes, multiple = lpegmatch(uparser,reference)
- if foundcodes then
- glyph.unicode = foundcodes
- if multiple then
- nl = nl + 1
- unicode = true
- else
- ns = ns + 1
- unicode = foundcodes
+ if not unicode or unicode == "" then
+ local foundcodes, multiple = lpegmatch(uparser,reference)
+ if foundcodes then
+ glyph.unicode = foundcodes
+ if multiple then
+ nl = nl + 1
+ unicode = true
+ else
+ ns = ns + 1
+ unicode = foundcodes
+ end
end
end
end
end
end
end
- end
- -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_
- --
- -- It is not trivial to find a solution that suits all fonts. We tried several alternatives
- -- and this one seems to work reasonable also with fonts that use less standardized naming
- -- schemes. The extra private test is tested by KE and seems to work okay with non-typical
- -- fonts as well.
- --
- if not unicode or unicode == "" then
- local split = lpegmatch(namesplitter,name)
- local nsplit = split and #split or 0 -- add if
- if nsplit == 0 then
- -- skip
- elseif nsplit == 1 then
- local base = split[1]
- local u = unicodes[base] or unicodevector[base] or contextvector[name]
- if not u then
+ -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_
+ --
+ -- It is not trivial to find a solution that suits all fonts. We tried several alternatives
+ -- and this one seems to work reasonable also with fonts that use less standardized naming
+ -- schemes. The extra private test is tested by KE and seems to work okay with non-typical
+ -- fonts as well.
+ --
+ if not unicode or unicode == "" then
+ local split = lpegmatch(namesplitter,name)
+ local nsplit = split and #split or 0 -- add if
+ if nsplit == 0 then
-- skip
- elseif type(u) == "table" then
- -- unlikely
- if u[1] < private then
- unicode = u
- glyph.unicode = unicode
- end
- elseif u < private then
- unicode = u
- glyph.unicode = unicode
- end
- else
- local t, n = { }, 0
- for l=1,nsplit do
- local base = split[l]
+ elseif nsplit == 1 then
+ local base = split[1]
local u = unicodes[base] or unicodevector[base] or contextvector[name]
if not u then
- break
+ -- skip
elseif type(u) == "table" then
- if u[1] >= private then
- break
+ -- unlikely
+ if u[1] < private then
+ unicode = u
+ glyph.unicode = unicode
end
- n = n + 1
- t[n] = u[1]
- else
- if u >= private then
+ elseif u < private then
+ unicode = u
+ glyph.unicode = unicode
+ end
+ else
+ local t, n = { }, 0
+ for l=1,nsplit do
+ local base = split[l]
+ local u = unicodes[base] or unicodevector[base] or contextvector[name]
+ if not u then
break
+ elseif type(u) == "table" then
+ if u[1] >= private then
+ break
+ end
+ n = n + 1
+ t[n] = u[1]
+ else
+ if u >= private then
+ break
+ end
+ n = n + 1
+ t[n] = u
+ end
+ end
+ if n > 0 then
+ if n == 1 then
+ unicode = t[1]
+ else
+ unicode = t
end
- n = n + 1
- t[n] = u
+ glyph.unicode = unicode
end
end
- if n > 0 then
- if n == 1 then
- unicode = t[1]
+ nl = nl + 1
+ end
+ -- last resort (we might need to catch private here as well)
+ if not unicode or unicode == "" then
+ local foundcodes, multiple = lpegmatch(uparser,name)
+ if foundcodes then
+ glyph.unicode = foundcodes
+ if multiple then
+ nl = nl + 1
+ unicode = true
else
- unicode = t
+ ns = ns + 1
+ unicode = foundcodes
end
- glyph.unicode = unicode
end
end
- nl = nl + 1
- end
- -- last resort (we might need to catch private here as well)
- if not unicode or unicode == "" then
- local foundcodes, multiple = lpegmatch(uparser,name)
- if foundcodes then
- glyph.unicode = foundcodes
- if multiple then
- nl = nl + 1
- unicode = true
- else
- ns = ns + 1
- unicode = foundcodes
- end
+ -- check using substitutes and alternates
+ local r = overloads[unicode]
+ if r then
+ unicode = r.unicode
+ glyph.unicode = unicode
+ end
+ --
+ if not unicode then
+ missing[du] = true
+ nofmissing = nofmissing + 1
end
- end
- -- check using substitutes and alternates
- local r = overloads[unicode]
- if r then
- unicode = r.unicode
- glyph.unicode = unicode
- end
- --
- if not unicode then
- missing[unic] = true
- nofmissing = nofmissing + 1
end
end
- else
- -- no name
end
end
if type(checklookups) == "function" then
diff --git a/src/fontloader/misc/fontloader-font-ocl.lua b/src/fontloader/misc/fontloader-font-ocl.lua
new file mode 100644
index 0000000..9661083
--- /dev/null
+++ b/src/fontloader/misc/fontloader-font-ocl.lua
@@ -0,0 +1,297 @@
+if not modules then modules = { } end modules ['font-ocl'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (context)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo : user list of colors
+
+local formatters = string.formatters
+
+local otf = fonts.handlers.otf
+
+local f_color_start = formatters["pdf:direct: %f %f %f rg"]
+local s_color_stop = "pdf:direct:"
+
+if context then
+
+ local startactualtext = nil
+ local stopactualtext = nil
+
+ function otf.getactualtext(n)
+ if not startactualtext then
+ startactualtext = backends.codeinjections.startunicodetoactualtext
+ stopactualtext = backends.codeinjections.stopunicodetoactualtext
+ end
+ return startactualtext(n), stopactualtext()
+ end
+
+else
+
+ local tounicode = fonts.mappings.tounicode16
+
+ function otf.getactualtext(n)
+ return "/Span << /ActualText <feff" .. tounicode(n) .. "> >> BDC", "EMC"
+ end
+
+end
+
+local function initializecolr(tfmdata,kind,value) -- hm, always value
+ if value then
+ local palettes = tfmdata.resources.colorpalettes
+ if palettes then
+ --
+ local palette = palettes[tonumber(value) or 1] or palettes[1] or { }
+ local classes = #palette
+ if classes == 0 then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ local colorvalues = { }
+ --
+ properties.virtualized = true
+ tfmdata.fonts = {
+ { id = 0 }
+ }
+ --
+ for i=1,classes do
+ local p = palette[i]
+ colorvalues[i] = { "special", f_color_start(p[1]/255,p[2]/255,p[3]/255) }
+ end
+ --
+ local getactualtext = otf.getactualtext
+ --
+ for unicode, character in next, characters do
+ local description = descriptions[unicode]
+ if description then
+ local colorlist = description.colors
+ if colorlist then
+ local b, e = getactualtext(unicode)
+ local w = character.width or 0
+ local s = #colorlist
+ local n = 1
+ local t = {
+ { "special", "pdf:direct: q " .. b }
+ }
+ for i=1,s do
+ local entry = colorlist[i]
+ n = n + 1 t[n] = colorvalues[entry.class]
+ n = n + 1 t[n] = { "char", entry.slot }
+ if s > 1 and i < s and w ~= 0 then
+ n = n + 1 t[n] = { "right", -w }
+ end
+ end
+ n = n + 1 t[n] = { "special", "pdf:direct:" .. e .. " Q" }
+ character.commands = t
+ end
+ end
+ end
+ end
+ end
+end
+
+fonts.handlers.otf.features.register {
+ name = "colr",
+ description = "color glyphs",
+ manipulators = {
+ base = initializecolr,
+ node = initializecolr,
+ }
+}
+
+local otfsvg = otf.svg or { }
+otf.svg = otfsvg
+otf.svgenabled = true
+
+do
+
+ local nofstreams = 0
+
+ -- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ]
+ -- local f_getstream = formatters[ [[svg-glyph-%05i]] ]
+
+ -- function otfsvg.storepdfdata(pdf)
+ -- nofstreams = nofstreams + 1
+ -- storepdfdata = function(pdf)
+ -- nofstreams = nofstreams + 1
+ -- return f_setstream(nofstreams,pdf), f_getstream(nofstreams)
+ -- end
+ -- end
+
+ local f_name = formatters[ [[svg-glyph-%05i]] ]
+ local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+
+ local cache = { }
+
+ function otfsvg.storepdfdata(pdf)
+ nofstreams = nofstreams + 1
+ local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
+ cache[n] = o -- we need to keep in mem
+ return nil, f_used(n), nil
+ end
+
+ if context then
+
+ local storepdfdata = otfsvg.storepdfdata
+ local initialized = false
+
+ function otfsvg.storepdfdata(pdf)
+ if not initialized then
+ if resolvers.setmemstream then
+ local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
+ local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ]
+ local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
+ storepdfdata = function(pdf)
+ nofstreams = nofstreams + 1
+ return
+ f_setstream(nofstreams,pdf),
+ f_getstream(nofstreams),
+ f_nilstream(nofstreams)
+ end
+ otfsvg.storepdfdata = storepdfdata
+ end
+ initialized = true
+ end
+ return storepdfdata(pdf)
+ end
+
+ end
+
+end
+
+if context and xml.convert then
+
+ local report_svg = logs.reporter("fonts","svg conversion")
+
+ 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 command = [[python "c:\Users\Hans Hagen\AppData\Roaming\Python\Scripts\cairosvg" -f pdf ]] .. svgfile .. " -o " .. pdffile
+ local testrun = false
+ local pdfshapes = { }
+ local nofshapes = #svgshapes
+ report_svg("processing %i svg containers",nofshapes)
+ for i=1,nofshapes do
+ local entry = svgshapes[i]
+ for j=entry.first,entry.last do
+ local svg = xml.convert(entry.data)
+ local data = xml.first(svg,"/svg[@id='glyph"..j.."']")
+ io.savedata(svgfile,tostring(data))
+ report_svg("processing svg shape of glyph %i in container %i",j,i)
+ os.execute(command)
+ pdfshapes[j] = io.loaddata(pdffile)
+ end
+ if testrun and i > testrun then
+ report_svg("quiting test run")
+ break
+ end
+ end
+ os.remove(svgfile)
+ 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
+ end
+ os.remove(svgfile)
+ texio.write("done]")
+ return pdfshapes
+ end
+
+end
+
+local function initializesvg(tfmdata,kind,value) -- hm, always value
+ if value and otf.svgenabled then
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ --
+ local svg = properties.svg
+ local hash = svg and svg.hash
+ local timestamp = svg and svg.timestamp
+ if not hash then
+ return
+ end
+ --
+ local pdffile = containers.read(otf.pdfcache,hash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp ~= timestamp then
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ pdfshapes = svgshapes and otfsvg.topdf(svgshapes) or { }
+ containers.write(otf.pdfcache, hash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ if not pdfshapes or not next(pdfshapes) then
+ return
+ end
+ --
+ properties.virtualized = true
+ tfmdata.fonts = {
+ { id = 0 }
+ }
+ --
+ local getactualtext = otf.getactualtext
+ local storepdfdata = otfsvg.storepdfdata
+ --
+ local nop = { "nop" }
+ --
+ for unicode, character in next, characters do
+ local index = character.index
+ if index then
+ local pdf = pdfshapes[index]
+ if pdf then
+ local setcode, name, nilcode = storepdfdata(pdf)
+ if name then
+ local bt, et = getactualtext(unicode)
+ local wd = character.width or 0
+ local ht = character.height or 0
+ local dp = character.depth or 0
+ character.commands = {
+ { "special", "pdf:direct:" .. bt },
+ { "down", dp },
+ setcode and { "lua", setcode } or nop,
+ { "image", { filename = name, width = wd, height = ht, depth = dp } },
+ nilcode and { "lua", nilcode } or nop,
+ { "special", "pdf:direct:" .. et },
+ }
+ character.svg = true
+ end
+ end
+ end
+ end
+ end
+end
+
+fonts.handlers.otf.features.register {
+ name = "svg",
+ description = "svg glyphs",
+ manipulators = {
+ base = initializesvg,
+ node = initializesvg,
+ }
+}
diff --git a/src/fontloader/misc/fontloader-font-afm.lua b/src/fontloader/misc/fontloader-font-one.lua
index 0d6b7cb..a6f47e8 100644
--- a/src/fontloader/misc/fontloader-font-afm.lua
+++ b/src/fontloader/misc/fontloader-font-one.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['font-afm'] = {
+if not modules then modules = { } end modules ['font-one'] = {
version = 1.001,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -7,33 +7,27 @@ if not modules then modules = { } end modules ['font-afm'] = {
}
--[[ldx--
-<p>Some code may look a bit obscure but this has to do with the
-fact that we also use this code for testing and much code evolved
-in the transition from <l n='tfm'/> to <l n='afm'/> to <l
-n='otf'/>.</p>
+<p>Some code may look a bit obscure but this has to do with the fact that we also use
+this code for testing and much code evolved in the transition from <l n='tfm'/> to
+<l n='afm'/> to <l n='otf'/>.</p>
-<p>The following code still has traces of intermediate font support
-where we handles font encodings. Eventually font encoding goes
-away.</p>
-
-<p>The embedding of a font involves creating temporary files and
-depending on your system setup that can fail. It took more than a
-day to figure out why sometimes embedding failed in mingw luatex
-where running on a real path like c:\... failed while running on
-say e:\... being a link worked well. The native windows binaries
-don't have this issue.</p>
+<p>The following code still has traces of intermediate font support where we handles
+font encodings. Eventually font encoding went away but we kept some code around in
+other modules.</p>
+<p>This version implements a node mode approach so that users can also more easily
+add features.</p>
--ldx]]--
local fonts, logs, trackers, containers, resolvers = fonts, logs, trackers, containers, resolvers
-local next, type, tonumber = next, type, tonumber
+local next, type, tonumber, rawget = next, type, tonumber, rawget
local match, gmatch, lower, gsub, strip, find = string.match, string.gmatch, 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, lpegmatch, patterns = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.match, lpeg.patterns
-local derivetable = table.derive
+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 lpegmatch, patterns = lpeg.match, lpeg.patterns
local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
@@ -43,6 +37,7 @@ local trace_defining = false trackers.register("fonts.defining", function(v
local report_afm = logs.reporter("fonts","afm loading")
local setmetatableindex = table.setmetatableindex
+local derivetable = table.derive
local findbinfile = resolvers.findbinfile
@@ -50,434 +45,67 @@ local definers = fonts.definers
local readers = fonts.readers
local constructors = fonts.constructors
-local afm = constructors.newhandler("afm")
-local pfb = constructors.newhandler("pfb")
+local afm = constructors.handlers.afm
+local pfb = constructors.handlers.pfb
+local otf = fonts.handlers.otf
+
+local otfreaders = otf.readers
+local otfenhancers = otf.enhancers
-local afmfeatures = constructors.newfeatures("afm")
+local afmfeatures = constructors.features.afm
local registerafmfeature = afmfeatures.register
-afm.version = 1.501 -- incrementing this number one up will force a re-cache
+afm.version = 1.512 -- incrementing this number one up will force a re-cache
afm.cache = containers.define("fonts", "afm", afm.version, true)
afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*)
afm.helpdata = { } -- set later on so no local for this
afm.syncspace = true -- when true, nicer stretch values
-afm.addligatures = true -- best leave this set to true
-afm.addtexligatures = true -- best leave this set to true
-afm.addkerns = true -- best leave this set to true
local overloads = fonts.mappings.overloads
local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
-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,
- }
-}
-
--[[ldx--
-<p>We start with the basic reader which we give a name similar to the
-built in <l n='tfm'/> and <l n='otf'/> reader.</p>
---ldx]]--
-
---~ Comment FONTIDENTIFIER LMMATHSYMBOLS10
---~ Comment CODINGSCHEME TEX MATH SYMBOLS
---~ Comment DESIGNSIZE 10.0 pt
---~ Comment CHECKSUM O 4261307036
---~ Comment SPACE 0 plus 0 minus 0
---~ Comment QUAD 1000
---~ Comment EXTRASPACE 0
---~ Comment NUM 676.508 393.732 443.731
---~ Comment DENOM 685.951 344.841
---~ Comment SUP 412.892 362.892 288.889
---~ Comment SUB 150 247.217
---~ Comment SUPDROP 386.108
---~ Comment SUBDROP 50
---~ Comment DELIM 2390 1010
---~ Comment AXISHEIGHT 250
-
-local comment = P("Comment")
-local spacing = patterns.spacer -- S(" \t")^1
-local lineend = patterns.newline -- S("\n\r")
-local words = C((1 - lineend)^1)
-local number = C((R("09") + S("."))^1) / tonumber * spacing^0
-local data = lpeg.Carg(1)
-
-local pattern = ( -- needs testing ... not used anyway as we no longer need math afm's
- comment * spacing *
- (
- data * (
- ("CODINGSCHEME" * spacing * words ) / function(fd,a) end +
- ("DESIGNSIZE" * spacing * number * words ) / function(fd,a) fd[ 1] = a end +
- ("CHECKSUM" * spacing * number * words ) / function(fd,a) fd[ 2] = a end +
- ("SPACE" * spacing * number * "plus" * number * "minus" * number) / function(fd,a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
- ("QUAD" * spacing * number ) / function(fd,a) fd[ 6] = a end +
- ("EXTRASPACE" * spacing * number ) / function(fd,a) fd[ 7] = a end +
- ("NUM" * spacing * number * number * number ) / function(fd,a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
- ("DENOM" * spacing * number * number ) / function(fd,a,b ) fd[11], fd[12] = a, b end +
- ("SUP" * spacing * number * number * number ) / function(fd,a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
- ("SUB" * spacing * number * number ) / function(fd,a,b) fd[16], fd[17] = a, b end +
- ("SUPDROP" * spacing * number ) / function(fd,a) fd[18] = a end +
- ("SUBDROP" * spacing * number ) / function(fd,a) fd[19] = a end +
- ("DELIM" * spacing * number * number ) / function(fd,a,b) fd[20], fd[21] = a, b end +
- ("AXISHEIGHT" * spacing * number ) / function(fd,a) fd[22] = a end
- )
- + (1-lineend)^0
- )
- + (1-comment)^1
-)^0
-
-local function scan_comment(str)
- local fd = { }
- lpegmatch(pattern,str,1,fd)
- return fd
-end
-
--- On a rainy day I will rewrite this in lpeg ... or we can use the (slower) fontloader
--- as in now supports afm/pfb loading but it's not too bad to have different methods
--- for testing approaches.
-
-local keys = { }
-
-function keys.FontName (data,line) data.metadata.fontname = strip (line) -- get rid of spaces
- data.metadata.fullname = strip (line) end
-function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end
-function keys.IsFixedPitch(data,line) data.metadata.monospaced = toboolean(line,true) end
-function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end
-function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end
-function keys.Descender (data,line) data.metadata.descender = tonumber (line) end
-function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end
-function keys.Comment (data,line)
- -- Comment DesignSize 12 (pts)
- -- Comment TFM designsize: 12 (in points)
- line = lower(line)
- local designsize = match(line,"designsize[^%d]*(%d+)")
- if designsize then data.metadata.designsize = tonumber(designsize) end
-end
-
-local function get_charmetrics(data,charmetrics,vector)
- local characters = data.characters
- local chr, ind = { }, 0
- for k, v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
- if k == 'C' then
- v = tonumber(v)
- if v < 0 then
- ind = ind + 1 -- ?
- else
- ind = v
- end
- chr = {
- index = ind
- }
- elseif k == 'WX' then
- chr.width = tonumber(v)
- elseif k == 'N' then
- characters[v] = chr
- elseif k == 'B' then
- local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
- chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
- elseif k == 'L' then
- local plus, becomes = match(v,"^(.-) +(.-)$")
- local ligatures = chr.ligatures
- if ligatures then
- ligatures[plus] = becomes
- else
- chr.ligatures = { [plus] = becomes }
- end
- end
- end
-end
-
-local function get_kernpairs(data,kernpairs)
- local characters = data.characters
- for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
- local chr = characters[one]
- if chr then
- local kerns = chr.kerns
- if kerns then
- kerns[two] = tonumber(value)
- else
- chr.kerns = { [two] = tonumber(value) }
- end
- end
- end
-end
-
-local function get_variables(data,fontmetrics)
- for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
- local keyhandler = keys[key]
- if keyhandler then
- keyhandler(data,rest)
- end
- end
-end
-
-local get_indexes
-
-do
-
- -- old font loader
-
- local fontloader = fontloader
- local get_indexes_old = false
-
- if fontloader then
-
- local font_to_table = fontloader.to_table
- local open_font = fontloader.open
- local close_font = fontloader.close
-
- get_indexes_old = function(data,pfbname)
- local pfbblob = open_font(pfbname)
- if pfbblob then
- local characters = data.characters
- local pfbdata = font_to_table(pfbblob)
- if pfbdata then
- local glyphs = pfbdata.glyphs
- if glyphs then
- if trace_loading then
- report_afm("getting index data from %a",pfbname)
- end
- for index, glyph in next, glyphs do
- local name = glyph.name
- if name then
- local char = characters[name]
- if char then
- if trace_indexing then
- report_afm("glyph %a has index %a",name,index)
- end
- char.index = index
- end
- end
- end
- elseif trace_loading then
- report_afm("no glyph data in pfb file %a",pfbname)
- end
- elseif trace_loading then
- report_afm("no data in pfb file %a",pfbname)
- end
- close_font(pfbblob)
- elseif trace_loading then
- report_afm("invalid pfb file %a",pfbname)
- end
- end
-
- end
-
- -- new (unfinished) font loader but i see no differences between
- -- old and new (one bad vector with old)
-
- local n, m
-
- local progress = function(str,position,name,size)
- local forward = position + tonumber(size) + 3 + 2
- n = n + 1
- if n >= m then
- return #str, name
- elseif forward < #str then
- return forward, name
- else
- return #str, name
- end
- end
-
- local initialize = function(str,position,size)
- n = 0
- m = 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 p_filternames = Ct (
- (1-charstrings)^0 * charstrings * spaces * Cmt(size,initialize)
- * (Cmt(name * P(" ")^1 * C(R("09")^1), progress) + P(1))^1
- )
-
- -- if one of first 4 not 0-9A-F then binary else hex
-
- local decrypt
-
- do
-
- local r, c1, c2, n = 0, 0, 0, 0
-
- local function step(c)
- local cipher = byte(c)
- local plain = bxor(cipher,rshift(r,8))
- r = ((cipher + r) * c1 + c2) % 65536
- return char(plain)
- end
-
- decrypt = function(binary)
- r, c1, c2, n = 55665, 52845, 22719, 4
- binary = gsub(binary,".",step)
- return sub(binary,n+1)
- end
-
- -- local pattern = Cs((P(1) / step)^1)
- --
- -- decrypt = function(binary)
- -- r, c1, c2, n = 55665, 52845, 22719, 4
- -- binary = lpegmatch(pattern,binary)
- -- return sub(binary,n+1)
- -- end
-
- end
-
- local function loadpfbvector(filename)
- -- for the moment limited to encoding only
-
- local data = io.loaddata(resolvers.findfile(filename))
-
- if not find(data,"!PS%-AdobeFont%-") then
- print("no font",filename)
- return
- end
-
- if not data then
- print("no data",filename)
- return
- end
-
- local ascii, binary = match(data,"(.*)eexec%s+......(.*)")
-
- if not binary then
- print("no binary",filename)
- return
- end
-
- binary = decrypt(binary,4)
-
- local vector = lpegmatch(p_filternames,binary)
-
- vector[0] = table.remove(vector,1)
-
- if not vector then
- print("no vector",filename)
- return
- end
-
- return vector
-
- end
-
- get_indexes = function(data,pfbname)
- local vector = loadpfbvector(pfbname)
- if vector then
- local characters = data.characters
- if trace_loading then
- report_afm("getting index data from %a",pfbname)
- end
- for index=1,#vector do
- local name = vector[index]
- local char = characters[name]
- if char then
- if trace_indexing then
- report_afm("glyph %a has index %a",name,index)
- end
- char.index = index
- end
- end
- end
- end
+<p>We cache files. Caching is taken care of in the loader. We cheat a bit by adding
+ligatures and kern information to the afm derived data. That way we can set them faster
+when defining a font.</p>
- if get_indexes_old then
-
- afm.use_new_indexer = true
- get_indexes_new = get_indexes
-
- get_indexes = function(data,pfbname)
- if afm.use_new_indexer then
- return get_indexes_new(data,pfbname)
- else
- return get_indexes_old(data,pfbname)
- end
- end
+<p>We still keep the loading two phased: first we load the data in a traditional
+fashion and later we transform it to sequences. Then we apply some methods also
+used in opentype fonts (like <t>tlig</t>).</p>
+--ldx]]--
- end
+local enhancers = {
+ -- It's cleaner to implement them after we've seen what we are
+ -- dealing with.
+}
-end
+local steps = {
+ "unify names",
+ "add ligatures",
+ "add extra kerns",
+ "normalize features",
+ "fix names",
+-- "add tounicode data",
+}
-local function readafm(filename)
- local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging
- if ok and afmblob then
- local data = {
- resources = {
- filename = resolvers.unresolve(filename),
- version = afm.version,
- creator = "context mkiv",
- },
- properties = {
- hasitalics = false,
- },
- goodies = {
- },
- metadata = {
- filename = file.removesuffix(file.basename(filename))
- },
- characters = {
- -- a temporary store
- },
- descriptions = {
- -- the final store
- },
- }
- afmblob = gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
+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_afm("loading char metrics")
+ report_afm("applying enhancer %a",step)
end
- get_charmetrics(data,charmetrics,vector)
- return ""
- end)
- afmblob = gsub(afmblob,"StartKernPairs(.-)EndKernPairs", function(kernpairs)
- if trace_loading then
- report_afm("loading kern pairs")
- end
- get_kernpairs(data,kernpairs)
- return ""
- end)
- afmblob = gsub(afmblob,"StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics)
- if trace_loading then
- report_afm("loading variables")
- end
- data.afmversion = version
- get_variables(data,fontmetrics)
- data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now
- return ""
- end)
- return data
- else
- if trace_loading then
- report_afm("no valid afm file %a",filename)
+ enhancer(data,filename)
+ else
+ report_afm("invalid enhancer %a",step)
end
- return nil
end
end
---[[ldx--
-<p>We cache files. Caching is taken care of in the loader. We cheat a bit
-by adding ligatures and kern information to the afm derived data. That
-way we can set them faster when defining a font.</p>
---ldx]]--
-
-local addkerns, addligatures, addtexligatures, unify, normalize, fixnames -- we will implement these later
-
function afm.load(filename)
- -- hm, for some reasons not resolved yet
filename = resolvers.findfile(filename,'afm') or ""
if filename ~= "" and not fonts.names.ignoredfile(filename) then
local name = file.removesuffix(file.basename(filename))
@@ -498,55 +126,42 @@ function afm.load(filename)
end
if not data or data.size ~= size or data.time ~= time or data.pfbsize ~= pfbsize or data.pfbtime ~= pfbtime then
report_afm("reading %a",filename)
- data = readafm(filename)
+ data = afm.readers.loadfont(filename,pfbname)
if data then
- if pfbname ~= "" then
- data.resources.filename = resolvers.unresolve(pfbname)
- get_indexes(data,pfbname)
- elseif trace_loading then
- report_afm("no pfb file for %a",filename)
- -- data.resources.filename = "unset" -- better than loading the afm file
- end
- report_afm("unifying %a",filename)
- unify(data,filename)
- if afm.addligatures then
- report_afm("add ligatures")
- addligatures(data)
- end
- if afm.addtexligatures then
- report_afm("add tex ligatures")
- addtexligatures(data)
- end
- if afm.addkerns then
- report_afm("add extra kerns")
- addkerns(data)
- end
- normalize(data)
- fixnames(data)
- report_afm("add tounicode data")
+ applyenhancers(data,filename)
+ -- otfreaders.addunicodetable(data) -- only when not done yet
fonts.mappings.addtounicode(data,filename)
+ -- otfreaders.extend(data)
+ otfreaders.pack(data)
data.size = size
data.time = time
data.pfbsize = pfbsize
data.pfbtime = pfbtime
report_afm("saving %a in cache",name)
- data.resources.unicodes = nil -- consistent with otf but here we save not much
+ -- data.resources.unicodes = nil -- consistent with otf but here we save not much
data = containers.write(afm.cache, name, data)
data = containers.read(afm.cache,name)
end
- if applyruntimefixes and data then
+ end
+ if data then
+ -- constructors.addcoreunicodes(unicodes)
+ otfreaders.unpack(data)
+ otfreaders.expand(data) -- inline tables
+ otfreaders.addunicodetable(data) -- only when not done yet
+ otfenhancers.apply(data,filename,data)
+ if applyruntimefixes then
applyruntimefixes(filename,data)
end
end
return data
- else
- return nil
end
end
-local uparser = fonts.mappings.makenameparser()
+-- we run a more advanced analyzer later on anyway
+
+local uparser = fonts.mappings.makenameparser() -- each time
-unify = function(data, filename)
+enhancers["unify names"] = function(data, filename)
local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
local unicodes = { }
local names = { }
@@ -556,7 +171,7 @@ unify = function(data, filename)
local code = unicodevector[name] -- or characters.name_to_unicode[name]
if not code then
code = lpegmatch(uparser,name)
- if not code then
+ if type(code) ~= "number" then
code = private
private = private + 1
report_afm("assigning private slot %U for unknown glyph name %a",code,name)
@@ -602,15 +217,108 @@ end
local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
local noflags = { false, false, false, false }
-afm.experimental_normalize = false
-
-normalize = function(data)
- if type(afm.experimental_normalize) == "function" then
- afm.experimental_normalize(data)
+enhancers["normalize features"] = function(data)
+ local ligatures = setmetatableindex("table")
+ local kerns = setmetatableindex("table")
+ local extrakerns = setmetatableindex("table")
+ for u, c in next, data.descriptions do
+ local l = c.ligatures
+ local k = c.kerns
+ local e = c.extrakerns
+ if l then
+ ligatures[u] = l
+ for u, v in next, l do
+ l[u] = { ligature = v }
+ 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
+ if e then
+ extrakerns[u] = e
+ for u, v in next, e do
+ e[u] = v -- { v, 0 }
+ end
+ c.extrakerns = nil
+ 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
+ if next(extrakerns) then
+ features.gpos.extrakerns = everywhere
+ data.properties.haskerns = true
+ sequences[#sequences+1] = {
+ features = {
+ extrakerns = everywhere,
+ },
+ flags = noflags,
+ name = "p_s_1",
+ nofsteps = 1,
+ order = { "extrakerns" },
+ type = "gpos_pair",
+ steps = {
+ {
+ format = "kern",
+ coverage = extrakerns,
+ },
+ },
+ }
+ end
+ -- todo: compress kerns
+ data.resources.features = features
+ data.resources.sequences = sequences
end
-fixnames = function(data)
+enhancers["fix names"] = function(data)
for k, v in next, data.descriptions do
local n = v.name
local r = overloads[n]
@@ -657,8 +365,13 @@ local addthem = function(rawdata,ligatures)
end
end
-addligatures = function(rawdata) addthem(rawdata,afm.helpdata.ligatures ) end
-addtexligatures = function(rawdata) addthem(rawdata,afm.helpdata.texligatures) end
+enhancers["add ligatures"] = function(rawdata)
+ addthem(rawdata,afm.helpdata.ligatures)
+end
+
+-- enhancers["add tex ligatures"] = function(rawdata)
+-- addthem(rawdata,afm.helpdata.texligatures)
+-- end
--[[ldx--
<p>We keep the extra kerns in separate kerning tables so that we can use
@@ -672,7 +385,7 @@ them selectively.</p>
-- we don't use the character database. (Ok, we can have a context specific
-- variant).
-addkerns = function(rawdata) -- using shcodes is not robust here
+enhancers["add extra kerns"] = function(rawdata) -- using shcodes is not robust here
local descriptions = rawdata.descriptions
local resources = rawdata.resources
local unicodes = resources.unicodes
@@ -864,11 +577,31 @@ local function copytotfm(data)
end
--
end
- local fd = data.fontdimens
- if fd and fd[8] and fd[9] and fd[10] then -- math
- for k,v in next, fd do
- parameters[k] = v
- end
+ --
+ if metadata.sup then
+ local dummy = { 0, 0, 0 }
+ parameters[ 1] = metadata.designsize or 0
+ parameters[ 2] = metadata.checksum or 0
+ parameters[ 3],
+ parameters[ 4],
+ parameters[ 5] = unpack(metadata.space or dummy)
+ parameters[ 6] = metadata.quad or 0
+ parameters[ 7] = metadata.extraspace or 0
+ parameters[ 8],
+ parameters[ 9],
+ parameters[10] = unpack(metadata.num or dummy)
+ parameters[11],
+ parameters[12] = unpack(metadata.denom or dummy)
+ parameters[13],
+ parameters[14],
+ parameters[15] = unpack(metadata.sup or dummy)
+ parameters[16],
+ parameters[17] = unpack(metadata.sub or dummy)
+ parameters[18] = metadata.supdrop or 0
+ parameters[19] = metadata.subdrop or 0
+ parameters[20],
+ parameters[21] = unpack(metadata.delim or dummy)
+ parameters[22] = metadata.axisheight or 0
end
--
parameters.designsize = (metadata.designsize or 10)*65536
@@ -900,10 +633,9 @@ local function copytotfm(data)
end
--[[ldx--
-<p>Originally we had features kind of hard coded for <l n='afm'/>
-files but since I expect to support more font formats, I decided
-to treat this fontformat like any other and handle features in a
-more configurable way.</p>
+<p>Originally we had features kind of hard coded for <l n='afm'/> files but since I
+expect to support more font formats, I decided to treat this fontformat like any
+other and handle features in a more configurable way.</p>
--ldx]]--
function afm.setfeatures(tfmdata,features)
@@ -982,6 +714,8 @@ local function afmtotfm(specification)
tfmdata.shared = shared
end
shared.rawdata = rawdata
+ shared.dynamics = { }
+ tfmdata.changed = { }
shared.features = features
shared.processes = afm.setfeatures(tfmdata,features)
end
@@ -1015,127 +749,34 @@ local function read_from_afm(specification)
end
--[[ldx--
-<p>Here comes the implementation of a few features. We only implement
-those that make sense for this format.</p>
+<p>We have the usual two modes and related features initializers and processors.</p>
--ldx]]--
-local function prepareligatures(tfmdata,ligatures,value)
- if value then
- local descriptions = tfmdata.descriptions
- local hasligatures = false
- for unicode, character in next, tfmdata.characters do
- local description = descriptions[unicode]
- local dligatures = description.ligatures
- if dligatures then
- local cligatures = character.ligatures
- if not cligatures then
- cligatures = { }
- character.ligatures = cligatures
- end
- for unicode, ligature in next, dligatures do
- cligatures[unicode] = {
- char = ligature,
- type = 0
- }
- end
- hasligatures = true
- end
- end
- tfmdata.properties.hasligatures = hasligatures
- end
-end
-
-local function preparekerns(tfmdata,kerns,value)
+local function setmode(tfmdata,value)
if value then
- local rawdata = tfmdata.shared.rawdata
- local resources = rawdata.resources
- local unicodes = resources.unicodes
- local descriptions = tfmdata.descriptions
- local haskerns = false
- for u, chr in next, tfmdata.characters do
- local d = descriptions[u]
- local newkerns = d[kerns]
- if newkerns then
- local kerns = chr.kerns
- if not kerns then
- kerns = { }
- chr.kerns = kerns
- end
- for k,v in next, newkerns do
- local uk = unicodes[k]
- if uk then
- kerns[uk] = v
- end
- end
- haskerns = true
- end
- end
- tfmdata.properties.haskerns = haskerns
- end
-end
-
-local list = {
- -- [0x0022] = 0x201D,
- [0x0027] = 0x2019,
- -- [0x0060] = 0x2018,
-}
-
-local function texreplacements(tfmdata,value)
- local descriptions = tfmdata.descriptions
- local characters = tfmdata.characters
- for k, v in next, list do
- characters [k] = characters [v] -- we forget about kerns
- descriptions[k] = descriptions[v] -- we forget about kerns
+ tfmdata.properties.mode = lower(value)
end
end
-local function ligatures (tfmdata,value) prepareligatures(tfmdata,'ligatures', value) end
-local function texligatures(tfmdata,value) prepareligatures(tfmdata,'texligatures',value) end
-local function kerns (tfmdata,value) preparekerns (tfmdata,'kerns', value) end
-local function extrakerns (tfmdata,value) preparekerns (tfmdata,'extrakerns', value) end
-
-registerafmfeature {
- name = "liga",
- description = "traditional ligatures",
- initializers = {
- base = ligatures,
- node = ligatures,
- }
-}
-
-registerafmfeature {
- name = "kern",
- description = "intercharacter kerning",
- initializers = {
- base = kerns,
- node = kerns,
- }
-}
-
-registerafmfeature {
- name = "extrakerns",
- description = "additional intercharacter kerning",
- initializers = {
- base = extrakerns,
- node = extrakerns,
- }
-}
-
registerafmfeature {
- name = 'tlig',
- description = 'tex ligatures',
+ name = "mode",
+ description = "mode",
initializers = {
- base = texligatures,
- node = texligatures,
+ base = setmode,
+ node = setmode,
}
}
registerafmfeature {
- name = 'trep',
- description = 'tex replacements',
+ name = "features",
+ description = "features",
+ default = true,
initializers = {
- base = texreplacements,
- node = texreplacements,
+ node = otf.nodemodeinitializer,
+ base = otf.basemodeinitializer,
+ },
+ processors = {
+ node = otf.featuresprocessor,
}
}
@@ -1171,7 +812,8 @@ local function check_afm(specification,fullname)
end
function readers.afm(specification,method)
- local fullname, tfmdata = specification.filename or "", nil
+ local fullname = specification.filename or ""
+ local tfmdata = nil
if fullname == "" then
local forced = specification.forced or ""
if forced ~= "" then
@@ -1200,7 +842,16 @@ function readers.pfb(specification,method) -- only called when forced
if trace_defining then
report_afm("using afm reader for %a",original)
end
- specification.specification = gsub(original,"%.pfb",".afm")
specification.forced = "afm"
+ local function swap(name)
+ local value = specification[swap]
+ if value then
+ specification[swap] = gsub("%.pfb",".afm",1)
+ end
+ end
+ swap("filename")
+ swap("fullname")
+ swap("forcedname")
+ swap("specification")
return readers.afm(specification,method)
end
diff --git a/src/fontloader/misc/fontloader-font-onr.lua b/src/fontloader/misc/fontloader-font-onr.lua
new file mode 100644
index 0000000..a4969ad
--- /dev/null
+++ b/src/fontloader/misc/fontloader-font-onr.lua
@@ -0,0 +1,411 @@
+if not modules then modules = { } end modules ['font-onr'] = {
+ 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"
+}
+
+--[[ldx--
+<p>Some code may look a bit obscure but this has to do with the fact that we also use
+this code for testing and much code evolved in the transition from <l n='tfm'/> to
+<l n='afm'/> to <l n='otf'/>.</p>
+
+<p>The following code still has traces of intermediate font support where we handles
+font encodings. Eventually font encoding went away but we kept some code around in
+other modules.</p>
+
+<p>This version implements a node mode approach so that users can also more easily
+add features.</p>
+--ldx]]--
+
+local fonts, logs, trackers, resolvers = fonts, logs, trackers, resolvers
+
+local next, type, tonumber, rawget = next, type, tonumber, rawget
+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 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 afm = handlers.afm or { }
+handlers.afm = afm
+local readers = afm.readers or { }
+afm.readers = readers
+
+afm.version = 1.512 -- incrementing this number one up will force a re-cache
+
+--[[ldx--
+<p>We start with the basic reader which we give a name similar to the built in <l n='tfm'/>
+and <l n='otf'/> reader.</p>
+<p>We use a new (unfinished) pfb loader but I see no differences between the old
+and new vectors (we actually had one bad vector with the old loader).</p>
+--ldx]]--
+
+local get_indexes
+
+do
+
+ local n, m
+
+ local progress = function(str,position,name,size)
+ local forward = position + tonumber(size) + 3 + 2
+ n = n + 1
+ if n >= m then
+ return #str, name
+ elseif forward < #str then
+ return forward, name
+ else
+ return #str, name
+ end
+ end
+
+ local initialize = function(str,position,size)
+ n = 0
+ m = 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 p_filternames = Ct (
+ (1-charstrings)^0 * charstrings * spaces * Cmt(size,initialize)
+ * (Cmt(name * P(" ")^1 * C(R("09")^1), progress) + P(1))^1
+ )
+
+ -- if one of first 4 not 0-9A-F then binary else hex
+
+ local decrypt
+
+ do
+
+ local r, c1, c2, n = 0, 0, 0, 0
+
+ local function step(c)
+ local cipher = byte(c)
+ local plain = bxor(cipher,rshift(r,8))
+ r = ((cipher + r) * c1 + c2) % 65536
+ return char(plain)
+ end
+
+ decrypt = function(binary)
+ r, c1, c2, n = 55665, 52845, 22719, 4
+ binary = gsub(binary,".",step)
+ return sub(binary,n+1)
+ end
+
+ -- local pattern = Cs((P(1) / step)^1)
+ --
+ -- decrypt = function(binary)
+ -- r, c1, c2, n = 55665, 52845, 22719, 4
+ -- binary = lpegmatch(pattern,binary)
+ -- return sub(binary,n+1)
+ -- end
+
+ end
+
+ local function loadpfbvector(filename)
+ -- for the moment limited to encoding only
+
+ local data = io.loaddata(resolvers.findfile(filename))
+
+ if not data then
+ report_pfb("no data in %a",filename)
+ return
+ end
+
+ if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then
+ report_pfb("no font in %a",filename)
+ return
+ end
+
+ local ascii, binary = match(data,"(.*)eexec%s+......(.*)")
+
+ if not binary then
+ report_pfb("no binary data in %a",filename)
+ return
+ end
+
+ binary = decrypt(binary,4)
+
+ local vector = lpegmatch(p_filternames,binary)
+
+ if vector[1] == ".notdef" then
+ -- tricky
+ vector[0] = table.remove(vector,1)
+ end
+
+ if not vector then
+ report_pfb("no vector in %a",filename)
+ return
+ end
+
+ return vector
+
+ end
+
+ get_indexes = function(data,pfbname)
+ local vector = loadpfbvector(pfbname)
+ if vector then
+ local characters = data.characters
+ if trace_loading then
+ report_afm("getting index data from %a",pfbname)
+ end
+ for index=1,#vector do
+ local name = vector[index]
+ local char = characters[name]
+ if char then
+ if trace_indexing then
+ report_afm("glyph %a has index %a",name,index)
+ end
+ char.index = index
+ end
+ end
+ end
+ end
+
+end
+
+--[[ldx--
+<p>We start with the basic reader which we give a name similar to the built in <l n='tfm'/>
+and <l n='otf'/> reader. We only need data that is relevant for our use. We don't support
+more complex arrangements like multiple master (obsolete), direction specific kerning, etc.</p>
+--ldx]]--
+
+local spacer = patterns.spacer
+local whitespace = patterns.whitespace
+local lineend = patterns.newline
+local spacing = spacer^0
+local number = spacing * S("+-")^-1 * (R("09") + S("."))^1 / tonumber
+local name = spacing * C((1 - whitespace)^1)
+local words = spacing * ((1 - lineend)^1 / strip)
+local rest = (1 - lineend)^0
+local fontdata = Carg(1)
+local semicolon = spacing * P(";")
+local plus = spacing * P("plus") * number
+local minus = spacing * P("minus") * number
+
+-- kern pairs
+
+local function addkernpair(data,one,two,value)
+ local chr = data.characters[one]
+ if chr then
+ local kerns = chr.kerns
+ if kerns then
+ kerns[two] = tonumber(value)
+ else
+ chr.kerns = { [two] = tonumber(value) }
+ end
+ end
+end
+
+local p_kernpair = (fontdata * P("KPX") * name * name * number) / addkernpair
+
+-- char metrics
+
+local chr = false
+local ind = 0
+
+local function start(data,version)
+ data.metadata.afmversion = version
+ ind = 0
+ chr = { }
+end
+
+local function stop()
+ ind = 0
+ chr = false
+end
+
+local function setindex(i)
+ if i < 0 then
+ ind = ind + 1 -- ?
+ else
+ ind = i
+ end
+ chr = {
+ index = ind
+ }
+end
+
+local function setwidth(width)
+ chr.width = width
+end
+
+local function setname(data,name)
+ data.characters[name] = chr
+end
+
+local function setboundingbox(boundingbox)
+ chr.boundingbox = boundingbox
+end
+
+local function setligature(plus,becomes)
+ local ligatures = chr.ligatures
+ if ligatures then
+ ligatures[plus] = becomes
+ else
+ chr.ligatures = { [plus] = becomes }
+ end
+end
+
+local p_charmetric = ( (
+ P("C") * number / setindex
+ + P("WX") * number / setwidth
+ + P("N") * fontdata * name / setname
+ + P("B") * Ct((number)^4) / setboundingbox
+ + P("L") * (name)^2 / setligature
+ ) * semicolon )^1
+
+local p_charmetrics = P("StartCharMetrics") * number * (p_charmetric + (1-P("EndCharMetrics")))^0 * P("EndCharMetrics")
+local p_kernpairs = P("StartKernPairs") * number * (p_kernpair + (1-P("EndKernPairs" )))^0 * P("EndKernPairs" )
+
+local function set_1(data,key,a) data.metadata[lower(key)] = a end
+local function set_2(data,key,a,b) data.metadata[lower(key)] = { a, b } end
+local function set_3(data,key,a,b,c) data.metadata[lower(key)] = { a, b, c } end
+
+-- Notice string
+-- EncodingScheme string
+-- MappingScheme integer
+-- EscChar integer
+-- CharacterSet string
+-- Characters integer
+-- IsBaseFont boolean
+-- VVector number number
+-- IsFixedV boolean
+
+local p_parameters = P(false)
+ + fontdata
+ * ((P("FontName") + P("FullName") + P("FamilyName"))/lower)
+ * words / function(data,key,value)
+ data.metadata[key] = value
+ end
+ + fontdata
+ * ((P("Weight") + P("Version"))/lower)
+ * name / function(data,key,value)
+ data.metadata[key] = value
+ end
+ + fontdata
+ * P("IsFixedPitch")
+ * name / function(data,pitch)
+ data.metadata.monospaced = toboolean(pitch,true)
+ end
+ + fontdata
+ * P("FontBBox")
+ * Ct(number^4) / function(data,boundingbox)
+ data.metadata.boundingbox = boundingbox
+ end
+ + fontdata
+ * ((P("CharWidth") + P("CapHeight") + P("XHeight") + P("Descender") + P("Ascender") + P("ItalicAngle"))/lower)
+ * number / function(data,key,value)
+ data.metadata[key] = value
+ end
+ + P("Comment") * spacing * ( P(false)
+ + (fontdata * C("DESIGNSIZE") * number * rest) / set_1 -- 1
+ + (fontdata * C("TFM designsize") * number * rest) / set_1
+ + (fontdata * C("DesignSize") * number * rest) / set_1
+ + (fontdata * C("CODINGSCHEME") * words * rest) / set_1 --
+ + (fontdata * C("CHECKSUM") * number * words * rest) / set_1 -- 2
+ + (fontdata * C("SPACE") * number * plus * minus * rest) / set_3 -- 3 4 5
+ + (fontdata * C("QUAD") * number * rest) / set_1 -- 6
+ + (fontdata * C("EXTRASPACE") * number * rest) / set_1 -- 7
+ + (fontdata * C("NUM") * number * number * number * rest) / set_3 -- 8 9 10
+ + (fontdata * C("DENOM") * number * number * rest) / set_2 -- 11 12
+ + (fontdata * C("SUP") * number * number * number * rest) / set_3 -- 13 14 15
+ + (fontdata * C("SUB") * number * number * rest) / set_2 -- 16 17
+ + (fontdata * C("SUPDROP") * number * rest) / set_1 -- 18
+ + (fontdata * C("SUBDROP") * number * rest) / set_1 -- 19
+ + (fontdata * C("DELIM") * number * number * rest) / set_2 -- 20 21
+ + (fontdata * C("AXISHEIGHT") * number * rest) / set_1 -- 22
+ )
+
+local fullparser = ( P("StartFontMetrics") * fontdata * name / start )
+ * ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0
+ * ( P("EndFontMetrics") / stop )
+
+local fullparser = ( P("StartFontMetrics") * fontdata * name / start )
+ * ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0
+ * ( P("EndFontMetrics") / stop )
+
+local infoparser = ( P("StartFontMetrics") * fontdata * name / start )
+ * ( p_parameters + (1-P("EndFontMetrics")) )^0
+ * ( P("EndFontMetrics") / stop )
+
+-- infoparser = ( P("StartFontMetrics") * fontdata * name / start )
+-- * ( p_parameters + (1-P("EndFontMetrics") - P("StartCharMetrics")) )^0
+-- * ( (P("EndFontMetrics") + P("StartCharMetrics")) / stop )
+
+local function read(filename,parser)
+ local afmblob = io.loaddata(filename)
+ if afmblob then
+ local data = {
+ resources = {
+ filename = resolvers.unresolve(filename),
+ version = afm.version,
+ creator = "context mkiv",
+ },
+ properties = {
+ hasitalics = false,
+ },
+ goodies = {
+ },
+ metadata = {
+ filename = file.removesuffix(file.basename(filename))
+ },
+ characters = {
+ -- a temporary store
+ },
+ descriptions = {
+ -- the final store
+ },
+ }
+ if trace_loading then
+ report_afm("parsing afm file %a",filename)
+ end
+ lpegmatch(parser,afmblob,1,data)
+ return data
+ else
+ if trace_loading then
+ report_afm("no valid afm file %a",filename)
+ end
+ return nil
+ end
+end
+
+function readers.loadfont(afmname,pfbname)
+ local data = read(resolvers.findfile(afmname),fullparser)
+ if data then
+ if not pfbname or pfbname == "" then
+ pfbname = file.replacesuffix(file.nameonly(afmname),"pfb")
+ pfbname = resolvers.findfile(pfbname)
+ end
+ if pfbname and pfbname ~= "" then
+ data.resources.filename = resolvers.unresolve(pfbname)
+ get_indexes(data,pfbname)
+ elseif trace_loading then
+ report_afm("no pfb file for %a",afmname)
+ -- data.resources.filename = "unset" -- better than loading the afm file
+ end
+ return data
+ end
+end
+
+function readers.getinfo(filename)
+ local data = read(resolvers.findfile(filename),infoparser)
+ if data then
+ return data.metadata
+ end
+end
diff --git a/src/fontloader/misc/fontloader-font-osd.lua b/src/fontloader/misc/fontloader-font-osd.lua
index 6ff2e38..a3dda67 100644
--- a/src/fontloader/misc/fontloader-font-osd.lua
+++ b/src/fontloader/misc/fontloader-font-osd.lua
@@ -79,13 +79,10 @@ fonts.analyzers.methods = fonts.analyzers.methods or { node = { otf = { } } }
local otf = fonts.handlers.otf
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-
local handlers = otf.handlers
local methods = fonts.analyzers.methods
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
local nuts = nodes.nuts
diff --git a/src/fontloader/misc/fontloader-font-ota.lua b/src/fontloader/misc/fontloader-font-ota.lua
index 6a3804a..4ddb831 100644
--- a/src/fontloader/misc/fontloader-font-ota.lua
+++ b/src/fontloader/misc/fontloader-font-ota.lua
@@ -44,7 +44,6 @@ local getchar = nuts.getchar
local ischar = nuts.is_char
local traverse_id = nuts.traverse_id
-local traverse_node_list = nuts.traverse
local end_of_math = nuts.end_of_math
local nodecodes = nodes.nodecodes
@@ -56,7 +55,7 @@ local fontdata = fonts.hashes.identifiers
local categories = characters and characters.categories or { } -- sorry, only in context
local chardata = characters and characters.data
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
--[[ldx--
diff --git a/src/fontloader/misc/fontloader-font-otd.lua b/src/fontloader/misc/fontloader-font-otd.lua
index 2257caa..64cb1bc 100644
--- a/src/fontloader/misc/fontloader-font-otd.lua
+++ b/src/fontloader/misc/fontloader-font-otd.lua
@@ -36,9 +36,6 @@ local contextmerged = specifiers.contextmerged
local setmetatableindex = table.setmetatableindex
-local otffeatures = fonts.constructors.newfeatures("otf")
-local registerotffeature = otffeatures.register
-
local a_to_script = { }
local a_to_language = { }
@@ -135,6 +132,10 @@ local wildcard = "*"
-- needs checking: some added features can pass twice
+local P, C, Cc, lpegmatch = lpeg.P, lpeg.C, lpeg.Cc, lpeg.match
+
+local pattern = P("always") * (P(-1) * Cc(true) + P(":") * C((1-P(-1))^1))
+
local function initialize(sequence,script,language,s_enabled,a_enabled,font,attr,dynamic,ra,autoscript,autolanguage)
local features = sequence.features
if features then
@@ -151,21 +152,34 @@ local function initialize(sequence,script,language,s_enabled,a_enabled,font,attr
e_e = s_enabled and s_enabled[kind] -- the value (font)
end
if e_e then
- local scripts = features[kind] --
- local languages = scripts[script] or scripts[wildcard]
- if not languages and autoscript then
- langages = defaultscript(featuretype,autoscript,scripts)
- end
- if languages then
- -- we need detailed control over default becase we want to trace
- -- only first attribute match check, so we assume simple fina's
- local valid = false
- if languages[language] then
- valid = e_e
- elseif languages[wildcard] then
- valid = e_e
- elseif autolanguage and defaultlanguage(featuretype,autolanguage,languages) then
- valid = e_e
+ local valid = type(e_e) == "string" and lpegmatch(pattern,e_e)
+ if valid then
+ -- we have hit always
+ local attribute = autofeatures[kind] or false
+ if trace_applied then
+ report_process(
+ "font %s, dynamic %a (%a), feature %a, script %a, language %a, lookup %a, value %a",
+ font,attr or 0,dynamic,kind,"*","*",sequence.name,valid)
+ end
+ ra[#ra+1] = { valid, attribute, sequence, kind }
+ else
+ -- we already checked for e_e
+ local scripts = features[kind] --
+ local languages = scripts[script] or scripts[wildcard]
+ if not languages and autoscript then
+ langages = defaultscript(featuretype,autoscript,scripts)
+ end
+ if languages then
+ -- we need detailed control over default becase we want to trace
+ -- only first attribute match check, so we assume simple fina's
+ -- local valid = false
+ if languages[language] then
+ valid = e_e
+ elseif languages[wildcard] then
+ valid = e_e
+ elseif autolanguage and defaultlanguage(featuretype,autolanguage,languages) then
+ valid = e_e
+ end
end
if valid then
local attribute = autofeatures[kind] or false
@@ -244,6 +258,7 @@ function otf.dataset(tfmdata,font,attr) -- attr only when explicit (as in specia
local autoscript = (s_enabled and s_enabled.autoscript ) or (a_enabled and a_enabled.autoscript )
local autolanguage = (s_enabled and s_enabled.autolanguage) or (a_enabled and a_enabled.autolanguage)
for s=1,#sequences do
+ -- just return nil or ra step
initialize(sequences[s],script,language,s_enabled,a_enabled,font,attr,dynamic,ra,autoscript,autolanguage)
end
end
diff --git a/src/fontloader/misc/fontloader-font-oti.lua b/src/fontloader/misc/fontloader-font-oti.lua
index bacd001..d74d2d5 100644
--- a/src/fontloader/misc/fontloader-font-oti.lua
+++ b/src/fontloader/misc/fontloader-font-oti.lua
@@ -11,8 +11,8 @@ local lower = string.lower
local fonts = fonts
local constructors = fonts.constructors
-local otf = constructors.newhandler("otf")
-local otffeatures = constructors.newfeatures("otf")
+local otf = constructors.handlers.otf
+local otffeatures = constructors.features.otf
local registerotffeature = otffeatures.register
local otftables = otf.tables or { }
diff --git a/src/fontloader/misc/fontloader-font-otj.lua b/src/fontloader/misc/fontloader-font-otj.lua
index 6ff80d8..d1408fd 100644
--- a/src/fontloader/misc/fontloader-font-otj.lua
+++ b/src/fontloader/misc/fontloader-font-otj.lua
@@ -24,10 +24,11 @@ if not modules then modules = { } end modules ['font-otj'] = {
-- The use_advance code is just a test and is meant for testing and manuals. There is no
-- performance (or whatever) gain and using kerns is somewhat cleaner (at least for now).
+-- Maybe: subtype fontkern when pure kerns.
+
if not nodes.properties then return end
local next, rawget = next, rawget
-local utfchar = utf.char
local fastcopy = table.fastcopy
local registertracker = trackers.register
@@ -92,7 +93,6 @@ local traverse_id = nuts.traverse_id
local traverse_char = nuts.traverse_char
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
-local find_tail = nuts.tail
local properties = nodes.properties.data
@@ -755,7 +755,7 @@ local function inject_pairs_only(head,where)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- insert_node_before(head,current,newkern(leftkern))
+ head = insert_node_before(head,current,newkern(leftkern))
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
@@ -1255,11 +1255,11 @@ local function inject_everything(head,where)
insert_node_after(pre,n,newkern(rightkern))
done = true
end
- end
- if hasmarks then
- local pm = i.markbasenode
- if pm then
- processmark(pm,current,i)
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
end
end
end
@@ -1287,11 +1287,11 @@ local function inject_everything(head,where)
insert_node_after(post,n,newkern(rightkern))
done = true
end
- end
- if hasmarks then
- local pm = i.markbasenode
- if pm then
- processmark(pm,current,i)
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
end
end
end
@@ -1319,11 +1319,11 @@ local function inject_everything(head,where)
insert_node_after(replace,n,newkern(rightkern))
done = true
end
- end
- if hasmarks then
- local pm = i.markbasenode
- if pm then
- processmark(pm,current,i)
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
end
end
end
@@ -1523,10 +1523,19 @@ function injections.handler(head,where)
head = injectspaces(head)
end
if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
+ if trace_injections then
+ report_injections("injection variant %a","everything")
+ end
return inject_everything(head,where)
elseif nofregisteredpairs > 0 then
+ if trace_injections then
+ report_injections("injection variant %a","pairs")
+ end
return inject_pairs_only(head,where)
elseif nofregisteredkerns > 0 then
+ if trace_injections then
+ report_injections("injection variant %a","kerns")
+ end
return inject_kerns_only(head,where)
else
return head, false
diff --git a/src/fontloader/misc/fontloader-font-otl.lua b/src/fontloader/misc/fontloader-font-otl.lua
index f7b6eb5..c7c278a 100644
--- a/src/fontloader/misc/fontloader-font-otl.lua
+++ b/src/fontloader/misc/fontloader-font-otl.lua
@@ -53,8 +53,12 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.019 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.022 -- 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)
+
+otf.svgenabled = false
local otfreaders = otf.readers
@@ -63,7 +67,7 @@ local definers = fonts.definers
local readers = fonts.readers
local constructors = fonts.constructors
-local otffeatures = constructors.newfeatures("otf")
+local otffeatures = constructors.features.otf
local registerotffeature = otffeatures.register
local enhancers = allocate()
@@ -101,6 +105,12 @@ registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef =
-- end
-- end
+-- Enhancers are used to apply fixes and extensions to fonts. For instance, we use them
+-- to implement tlig and trep features. They are not neccessarily bound to opentype
+-- fonts but can also apply to type one fonts, given that they obey the structure of an
+-- opentype font. They are not to be confused with format specific features but maybe
+-- some are so generic that they might eventually move to this mechanism.
+
local ordered_enhancers = {
"check extra features",
}
@@ -264,6 +274,25 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
--
--
if data then
+ --
+ local resources = data.resources
+ local svgshapes = resources.svgshapes
+ if svgshapes then
+ resources.svgshapes = nil
+ if otf.svgenabled then
+ local timestamp = os.date()
+ -- work in progress ... a bit boring to do
+ containers.write(otf.svgcache,hash, {
+ svgshapes = svgshapes,
+ timestamp = timestamp,
+ })
+ data.properties.svg = {
+ hash = hash,
+ timestamp = timestamp,
+ }
+ end
+ end
+ --
otfreaders.compact(data)
otfreaders.rehash(data,"unicodes")
otfreaders.addunicodetable(data)
@@ -302,7 +331,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
--
enhancers.apply(data,filename,data)
--
- constructors.addcoreunicodes(unicodes)
+ -- constructors.addcoreunicodes(data.resources.unicodes) -- still needed ?
--
if applyruntimefixes then
applyruntimefixes(filename,data)
@@ -340,7 +369,6 @@ end
local function copytotfm(data,cache_id)
if data then
local metadata = data.metadata
- local resources = data.resources
local properties = derivetable(data.properties)
local descriptions = derivetable(data.descriptions)
local goodies = derivetable(data.goodies)
diff --git a/src/fontloader/misc/fontloader-font-oto.lua b/src/fontloader/misc/fontloader-font-oto.lua
index b7ee717..1199778 100644
--- a/src/fontloader/misc/fontloader-font-oto.lua
+++ b/src/fontloader/misc/fontloader-font-oto.lua
@@ -14,8 +14,6 @@ local concat, unpack = table.concat, table.unpack
local insert, remove = table.insert, table.remove
local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
local type, next, tonumber, tostring, rawget = type, next, tonumber, tostring, rawget
-local lpegmatch = lpeg.match
-local utfchar = utf.char
local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
@@ -450,3 +448,5 @@ registerotffeature {
base = featuresinitializer,
}
}
+
+otf.basemodeinitializer = featuresinitializer
diff --git a/src/fontloader/misc/fontloader-font-otr.lua b/src/fontloader/misc/fontloader-font-otr.lua
index 24f6854..7d0bf04 100644
--- a/src/fontloader/misc/fontloader-font-otr.lua
+++ b/src/fontloader/misc/fontloader-font-otr.lua
@@ -99,7 +99,7 @@ readers.streamreader = streamreader
local openfile = streamreader.open
local closefile = streamreader.close
-local skipbytes = streamreader.skip
+----- skipbytes = streamreader.skip
local setposition = streamreader.setposition
local skipshort = streamreader.skipshort
local readbytes = streamreader.readbytes
@@ -108,7 +108,7 @@ local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
-local readchar = streamreader.readinteger1 -- 8-bit signed integer
+----- readchar = streamreader.readinteger1 -- 8-bit signed integer
local readshort = streamreader.readinteger2 -- 16-bit signed integer
local readlong = streamreader.readinteger4 -- 24-bit unsigned integer
local readfixed = streamreader.readfixed4
@@ -129,12 +129,11 @@ local function readlongdatetime(f)
return 0x100000000 * d + 0x1000000 * e + 0x10000 * f + 0x100 * g + h
end
-local tableversion = 0.004
-local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF
+local tableversion = 0.004
+readers.tableversion = tableversion
+local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF
+local reportedskipped = { }
-readers.tableversion = tableversion
-
-local reportedskipped = { }
local function reportskippedtable(tag)
if not reportedskipped[tag] then
@@ -1657,6 +1656,26 @@ function readers.glyf(f,fontdata,specification) -- part goes to cff module
end
end
+-- Experimental (we need fonts).
+
+function readers.colr(f,fontdata,specification)
+ if specification.glyphs then
+ reportskippedtable("colr")
+ end
+end
+
+function readers.cpal(f,fontdata,specification)
+ if specification.glyphs then
+ reportskippedtable("cpal")
+ end
+end
+
+function readers.svg(f,fontdata,specification)
+ if specification.glyphs then
+ reportskippedtable("svg")
+ end
+end
+
-- Here we have a table that we really need for later processing although a more advanced gpos table
-- can also be available. Todo: we need a 'fake' lookup for this (analogue to ff).
@@ -1874,6 +1893,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames)
-- format = fontdata.format,
fontname = fontname,
fullname = fullname,
+ -- cfffullname = cff.fullname,
family = family,
subfamily = subfamily,
familyname = familyname,
@@ -1996,6 +2016,9 @@ local function readdata(f,offset,specification)
readers["cmap"](f,fontdata,specification)
readers["loca"](f,fontdata,specification)
readers["glyf"](f,fontdata,specification)
+ readers["colr"](f,fontdata,specification)
+ readers["cpal"](f,fontdata,specification)
+ readers["svg" ](f,fontdata,specification)
readers["kern"](f,fontdata,specification)
readers["gdef"](f,fontdata,specification)
readers["gsub"](f,fontdata,specification)
@@ -2164,7 +2187,9 @@ function readers.loadfont(filename,n)
goodies = { },
metadata = getinfo(fontdata,n), -- no platformnames here !
properties = {
- hasitalics = fontdata.hasitalics or false,
+ hasitalics = fontdata.hasitalics or false,
+ maxcolorclass = fontdata.maxcolorclass,
+ hascolor = fontdata.hascolor or false,
},
resources = {
-- filename = fontdata.filename,
@@ -2181,6 +2206,8 @@ function readers.loadfont(filename,n)
version = getname(fontdata,"version"),
cidinfo = fontdata.cidinfo,
mathconstants = fontdata.mathconstants,
+ colorpalettes = fontdata.colorpalettes,
+ svgshapes = fontdata.svgshapes,
},
}
end
diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua
index 21225c2..51704bf 100644
--- a/src/fontloader/misc/fontloader-font-ots.lua
+++ b/src/fontloader/misc/fontloader-font-ots.lua
@@ -124,7 +124,7 @@ local trace_cursive = false registertracker("otf.cursive", function(v
local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end)
local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end)
local trace_details = false registertracker("otf.details", function(v) trace_details = v end)
-local trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end)
+----- trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end)
local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end)
local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end)
@@ -145,10 +145,8 @@ local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
local report_process = logs.reporter("fonts","otf process")
------ report_prepare = logs.reporter("fonts","otf prepare")
local report_warning = logs.reporter("fonts","otf warning")
local report_run = logs.reporter("fonts","otf run")
-local report_check = logs.reporter("fonts","otf check")
registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
@@ -185,10 +183,7 @@ local setlink = nuts.setlink
local ischar = nuts.is_char
-local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
-local delete_node = nuts.delete
-local remove_node = nuts.remove
local copy_node = nuts.copy
local copy_node_list = nuts.copy_list
local find_node_tail = nuts.tail
@@ -244,7 +239,7 @@ local cursonce = true
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
local onetimemessage = fonts.loggers.onetimemessage or function() end
@@ -3064,7 +3059,7 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm
while start do
local char = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if not a or (a == attr) then
local lookupmatch = lookupcache[char]
if lookupmatch then
@@ -3097,7 +3092,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
while start ~= stop do
local char = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if not a or (a == attr) then
local lookupmatch = lookupcache[char]
if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check
@@ -3132,7 +3127,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
end
-- local function d_run_single(prev,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
--- local a = getattr(prev,0)
+-- local a = attr and getattr(prev,0)
-- if not a or (a == attr) then
-- local char = ischar(prev) -- can be disc
-- if char then
@@ -3149,7 +3144,7 @@ end
-- end
local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- local a = getattr(sub,0)
+ local a = attr and getattr(sub,0)
if not a or (a == attr) then
for n in traverse_nodes(sub) do -- only gpos
if n == last then
@@ -3181,7 +3176,7 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
while start do
local char = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if not a or (a == attr) then
for i=1,nofsteps do
local step = steps[i]
@@ -3228,7 +3223,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
while start ~= stop do
local char = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if not a or (a == attr) then
for i=1,nofsteps do
local step = steps[i]
@@ -3271,7 +3266,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
end
-- local function d_run_multiple(prev,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
--- local a = getattr(prev,0)
+-- local a = attr and getattr(prev,0)
-- if not a or (a == attr) then
-- local char = ischar(prev) -- can be disc
-- if char then
@@ -3297,7 +3292,7 @@ end
-- end
local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- local a = getattr(sub,0)
+ local a = attr and getattr(sub,0)
if not a or (a == attr) then
for n in traverse_nodes(sub) do -- only gpos
if n == last then
@@ -3394,6 +3389,14 @@ local function featuresprocessor(head,font,attr)
end
+ -- some 10% faster when no dynamics but hardly measureable on real runs .. but: it only
+ -- works when we have no other dynamics as otherwise the zero run will be applied to the
+ -- whole stream for which we then need to pass another variable which we won't
+
+ -- if attr == 0 then
+ -- attr = false
+ -- end
+
head = tonut(head)
if trace_steps then
@@ -3405,7 +3408,7 @@ local function featuresprocessor(head,font,attr)
local done = false
local datasets = otf.dataset(tfmdata,font,attr)
- local dirstack = { } -- could move outside function btu we can have local runss
+ local dirstack = { } -- could move outside function but we can have local runs
sweephead = { }
@@ -3451,7 +3454,7 @@ local function featuresprocessor(head,font,attr)
while start do
local char = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if not a or (a == attr) then
for i=1,nofsteps do
local step = steps[i]
@@ -3485,18 +3488,15 @@ local function featuresprocessor(head,font,attr)
local start = head -- local ?
rlmode = 0 -- to be checked ?
if nofsteps == 1 then -- happens often
-
local step = steps[1]
local lookupcache = step.coverage
if not lookupcache then
- -- can't happen, no check in loop either
report_missing_coverage(dataset,sequence)
else
-
while start do
local char, id = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
else
@@ -3553,7 +3553,7 @@ local function featuresprocessor(head,font,attr)
while start do
local char, id = ischar(start,font)
if char then
- local a = getattr(start,0)
+ local a = attr and getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
else
@@ -3652,6 +3652,9 @@ registerotffeature {
}
}
+otf.nodemodeinitializer = featuresinitializer
+otf.featuresprocessor = featuresprocessor
+
-- This can be used for extra handlers, but should be used with care!
otf.handlers = handlers -- used in devanagari
diff --git a/src/fontloader/misc/fontloader-font-oup.lua b/src/fontloader/misc/fontloader-font-oup.lua
index 3b6d8ea..e2d209a 100644
--- a/src/fontloader/misc/fontloader-font-oup.lua
+++ b/src/fontloader/misc/fontloader-font-oup.lua
@@ -586,7 +586,8 @@ local function checklookups(fontdata,missing,nofmissing)
local done = { }
for i, r in next, missing do
if r then
- local name = descriptions[i].name or f_index(i)
+ local data = descriptions[i]
+ local name = data and data.name or f_index(i)
if not ignore[name] then
done[name] = true
end
@@ -706,6 +707,19 @@ local function unifyglyphs(fontdata,usenames)
end
end
--
+ local colorpalettes = resources.colorpalettes
+ if colorpalettes then
+ for index=1,#glyphs do
+ local colors = glyphs[index].colors
+ if colors then
+ for i=1,#colors do
+ local c = colors[i]
+ c.slot = indices[c.slot]
+ end
+ end
+ end
+ end
+ --
fontdata.private = private
fontdata.glyphs = nil
fontdata.names = names
@@ -1158,6 +1172,7 @@ function readers.pack(data)
local sequences = resources.sequences
local sublookups = resources.sublookups
local features = resources.features
+ local palettes = resources.colorpalettes
local chardata = characters and characters.data
local descriptions = data.descriptions or data.glyphs
@@ -1190,6 +1205,14 @@ function readers.pack(data)
end
end
end
+ -- if palettes then
+ -- local color = description.color
+ -- if color then
+ -- for i=1,#color do
+ -- color[i] = pack_normal(color[i])
+ -- end
+ -- end
+ -- end
end
local function packthem(sequences)
@@ -1314,6 +1337,16 @@ function readers.pack(data)
end
end
+ if palettes then
+ for i=1,#palettes do
+ local p = palettes[i]
+ for j=1,#p do
+ p[j] = pack_indexed(p[j])
+ end
+ end
+
+ end
+
if not success(1,pass) then
return
end
@@ -1461,6 +1494,7 @@ function readers.unpack(data)
local sequences = resources.sequences
local sublookups = resources.sublookups
local features = resources.features
+ local palettes = resources.colorpalettes
local unpacked = { }
setmetatable(unpacked,unpacked_mt)
for unicode, description in next, descriptions do
@@ -1487,6 +1521,17 @@ function readers.unpack(data)
end
end
end
+ -- if palettes then
+ -- local color = description.color
+ -- if color then
+ -- for i=1,#color do
+ -- local tv = tables[color[i]]
+ -- if tv then
+ -- color[i] = tv
+ -- end
+ -- end
+ -- end
+ -- end
end
local function unpackthem(sequences)
@@ -1716,6 +1761,18 @@ function readers.unpack(data)
end
end
+ if palettes then
+ for i=1,#palettes do
+ local p = palettes[i]
+ for j=1,#p do
+ local tv = tables[p[j]]
+ if tv then
+ p[j] = tv
+ end
+ end
+ end
+ end
+
data.tables = nil
end
end
diff --git a/src/fontloader/misc/fontloader-font-tfm.lua b/src/fontloader/misc/fontloader-font-tfm.lua
index 8e92c48..ab6d795 100644
--- a/src/fontloader/misc/fontloader-font-tfm.lua
+++ b/src/fontloader/misc/fontloader-font-tfm.lua
@@ -23,13 +23,13 @@ local readers = fonts.readers
local constructors = fonts.constructors
local encodings = fonts.encodings
-local tfm = constructors.newhandler("tfm")
+local tfm = constructors.handlers.tfm
tfm.version = 1.000
tfm.maxnestingdepth = 5
tfm.maxnestingsize = 65536*1024
-local tfmfeatures = constructors.newfeatures("tfm")
-local registertfmfeature = tfmfeatures.register
+local tfmfeatures = constructors.features.tfm
+----- registertfmfeature = tfmfeatures.register
constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua
diff --git a/src/fontloader/misc/fontloader-fonts-ext.lua b/src/fontloader/misc/fontloader-fonts-ext.lua
index b60d045..9d8d307 100644
--- a/src/fontloader/misc/fontloader-fonts-ext.lua
+++ b/src/fontloader/misc/fontloader-fonts-ext.lua
@@ -12,7 +12,7 @@ if context then
end
local fonts = fonts
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = fonts.constructors.features.otf
-- A few generic extensions.
diff --git a/src/fontloader/misc/fontloader-fonts.lua b/src/fontloader/misc/fontloader-fonts.lua
index e1ec376..83d52d9 100644
--- a/src/fontloader/misc/fontloader-fonts.lua
+++ b/src/fontloader/misc/fontloader-fonts.lua
@@ -186,6 +186,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule("l-file.lua")
loadmodule("l-boolean.lua")
loadmodule("l-math.lua")
+ loadmodule("l-unicode.lua")
-- A few slightly higher level support modules:
@@ -230,8 +231,6 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('luatex-fonts-syn.lua')
loadmodule('font-tfm.lua')
- loadmodule('font-afm.lua')
- loadmodule('font-afk.lua')
loadmodule('font-oti.lua')
-- These are the old loader and processing modules. These use the built-in font loader and
@@ -259,6 +258,13 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('font-ota.lua')
loadmodule('font-ots.lua')
loadmodule('font-osd.lua')
+ loadmodule('font-ocl.lua') -- svg needs 0.97 (for fix in memstreams)
+
+ -- type one code
+
+ loadmodule('font-onr.lua') -- was font-afm.lua
+ loadmodule('font-one.lua') -- was font-afm.lua
+ loadmodule('font-afk.lua')
-- common code
diff --git a/src/fontloader/misc/fontloader-math.tex b/src/fontloader/misc/fontloader-math.tex
index 604b4a1..b249021 100644
--- a/src/fontloader/misc/fontloader-math.tex
+++ b/src/fontloader/misc/fontloader-math.tex
@@ -40,9 +40,9 @@
\font\tenbf = file:lmroman10-bold.otf:+liga;+kern;+tlig;+trep at 10pt
\font\tenbi = file:lmroman10-bolditalic.otf:+liga;+kern;+tlig;+trep at 10pt
%
- \font\mathfonttextupright = file:latinmodern-math.otf:ssty=0;fixmath=yes at 10pt
- \font\mathfontscriptupright = file:latinmodern-math.otf:ssty=1;fixmath=yes at 7pt
- \font\mathfontscriptscriptupright = file:latinmodern-math.otf:ssty=2;fixmath=yes at 5pt
+ \font\mathfonttextupright = file:latinmodern-math.otf:script=math;ssty=0;mathsize=yes at 10pt
+ \font\mathfontscriptupright = file:latinmodern-math.otf:script=math;ssty=1;mathsize=yes at 7pt
+ \font\mathfontscriptscriptupright = file:latinmodern-math.otf:script=math;ssty=2;mathsize=yes at 5pt
%
\textfont 0 = \mathfonttextupright
\scriptfont 0 = \mathfontscriptupright
@@ -61,9 +61,9 @@
\font\tenbf = file:lucidabrightot-demi.otf:+liga;+kern;+tlig;+trep at 10pt
\font\tenbi = file:lucidabrightot-demiitalic.otf:+liga;+kern;+tlig;+trep at 10pt
%
- \font\mathfonttextupright = file:lucidabrightmathot.otf:ssty=0;fixmath=yes at 10pt
- \font\mathfontscriptupright = file:lucidabrightmathot.otf:ssty=1;fixmath=yes at 7pt
- \font\mathfontscriptscriptupright = file:lucidabrightmathot.otf:ssty=2;fixmath=yes at 5pt
+ \font\mathfonttextupright = file:lucidabrightmathot.otf:script=math;ssty=0;mathsize=yes at 10pt
+ \font\mathfontscriptupright = file:lucidabrightmathot.otf:script=math;ssty=1;mathsize=yes at 7pt
+ \font\mathfontscriptscriptupright = file:lucidabrightmathot.otf:script=math;ssty=2;mathsize=yes at 5pt
%
\textfont 0 = \mathfonttextupright
\scriptfont 0 = \mathfontscriptupright