diff options
Diffstat (limited to 'tex/generic')
17 files changed, 9991 insertions, 9991 deletions
diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua index 4c504a24e..0561778b4 100644 --- a/tex/generic/context/luatex/luatex-basics-gen.lua +++ b/tex/generic/context/luatex/luatex-basics-gen.lua @@ -1,327 +1,327 @@ -if not modules then modules = { } end modules ['luat-basics-gen'] = {
- version = 1.100,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local dummyfunction = function()
-end
-
-local dummyreporter = function(c)
- return function(...)
- (texio.reporter or texio.write_nl)(c .. " : " .. string.formatters(...))
- end
-end
-
-statistics = {
- register = dummyfunction,
- starttiming = dummyfunction,
- stoptiming = dummyfunction,
- elapsedtime = nil,
-}
-
-directives = {
- register = dummyfunction,
- enable = dummyfunction,
- disable = dummyfunction,
-}
-
-trackers = {
- register = dummyfunction,
- enable = dummyfunction,
- disable = dummyfunction,
-}
-
-experiments = {
- register = dummyfunction,
- enable = dummyfunction,
- disable = dummyfunction,
-}
-
-storage = { -- probably no longer needed
- register = dummyfunction,
- shared = { },
-}
-
-logs = {
- new = dummyreporter,
- reporter = dummyreporter,
- messenger = dummyreporter,
- report = dummyfunction,
-}
-
-callbacks = {
- register = function(n,f) return callback.register(n,f) end,
-
-}
-
-utilities = {
- storage = {
- allocate = function(t) return t or { } end,
- mark = function(t) return t or { } end,
- },
-}
-
-characters = characters or {
- data = { }
-}
-
--- we need to cheat a bit here
-
-texconfig.kpse_init = true
-
-resolvers = resolvers or { } -- no fancy file helpers used
-
-local remapper = {
- otf = "opentype fonts",
- ttf = "truetype fonts",
- ttc = "truetype fonts",
- dfont = "truetype fonts", -- "truetype dictionary",
- cid = "cid maps",
- cidmap = "cid maps",
- fea = "font feature files",
- pfa = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
- pfb = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
-}
-
-function resolvers.findfile(name,fileformat)
- name = string.gsub(name,"\\","/")
- if not fileformat or fileformat == "" then
- fileformat = file.suffix(name)
- if fileformat == "" then
- fileformat = "tex"
- end
- end
- fileformat = string.lower(fileformat)
- fileformat = remapper[fileformat] or fileformat
- local found = kpse.find_file(name,fileformat)
- if not found or found == "" then
- found = kpse.find_file(name,"other text files")
- end
- return found
-end
-
--- function resolvers.findbinfile(name,fileformat)
--- if not fileformat or fileformat == "" then
--- fileformat = file.suffix(name)
--- end
--- return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
--- end
-
-resolvers.findbinfile = resolvers.findfile
-
-function resolvers.resolve(s)
- return s
-end
-
-function resolvers.unresolve(s)
- return s
-end
-
--- Caches ... I will make a real stupid version some day when I'm in the
--- mood. After all, the generic code does not need the more advanced
--- ConTeXt features. Cached data is not shared between ConTeXt and other
--- usage as I don't want any dependency at all. Also, ConTeXt might have
--- different needs and tricks added.
-
---~ containers.usecache = true
-
-caches = { }
-
-local writable = nil
-local readables = { }
-local usingjit = jit
-
-if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then
- caches.namespace = 'generic'
-end
-
-do
-
- -- standard context tree setup
-
- local cachepaths = kpse.expand_path('$TEXMFCACHE') or ""
-
- -- quite like tex live or so
-
- if cachepaths == "" then
- cachepaths = kpse.expand_path('$TEXMFVAR')
- end
-
- -- this also happened to be used
-
- if cachepaths == "" then
- cachepaths = kpse.expand_path('$VARTEXMF')
- end
-
- -- and this is a last resort
-
- if cachepaths == "" then
- cachepaths = "."
- end
-
- cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":")
-
- for i=1,#cachepaths do
- local cachepath = cachepaths[i]
- if not lfs.isdir(cachepath) then
- lfs.mkdirs(cachepath) -- needed for texlive and latex
- if lfs.isdir(cachepath) then
- texio.write(string.format("(created cache path: %s)",cachepath))
- end
- end
- if file.is_writable(cachepath) then
- writable = file.join(cachepath,"luatex-cache")
- lfs.mkdir(writable)
- writable = file.join(writable,caches.namespace)
- lfs.mkdir(writable)
- break
- end
- end
-
- for i=1,#cachepaths do
- if file.is_readable(cachepaths[i]) then
- readables[#readables+1] = file.join(cachepaths[i],"luatex-cache",caches.namespace)
- end
- end
-
- if not writable then
- texio.write_nl("quiting: fix your writable cache path")
- os.exit()
- elseif #readables == 0 then
- texio.write_nl("quiting: fix your readable cache path")
- os.exit()
- elseif #readables == 1 and readables[1] == writable then
- texio.write(string.format("(using cache: %s)",writable))
- else
- texio.write(string.format("(using write cache: %s)",writable))
- texio.write(string.format("(using read cache: %s)",table.concat(readables, " ")))
- end
-
-end
-
-function caches.getwritablepath(category,subcategory)
- local path = file.join(writable,category)
- lfs.mkdir(path)
- path = file.join(path,subcategory)
- lfs.mkdir(path)
- return path
-end
-
-function caches.getreadablepaths(category,subcategory)
- local t = { }
- for i=1,#readables do
- t[i] = file.join(readables[i],category,subcategory)
- end
- return t
-end
-
-local function makefullname(path,name)
- if path and path ~= "" then
- return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),usingjit and "lub" or "luc")
- end
-end
-
-function caches.is_writable(path,name)
- local fullname = makefullname(path,name)
- return fullname and file.is_writable(fullname)
-end
-
-function caches.loaddata(paths,name)
- for i=1,#paths do
- local data = false
- local luaname, lucname = makefullname(paths[i],name)
- if lucname and lfs.isfile(lucname) then -- maybe also check for size
- texio.write(string.format("(load luc: %s)",lucname))
- data = loadfile(lucname)
- if data then
- data = data()
- end
- if data then
- return data
- else
- texio.write(string.format("(loading failed: %s)",lucname))
- end
- end
- if luaname and lfs.isfile(luaname) then
- texio.write(string.format("(load lua: %s)",luaname))
- data = loadfile(luaname)
- if data then
- data = data()
- end
- if data then
- return data
- end
- end
- end
-end
-
-function caches.savedata(path,name,data)
- local luaname, lucname = makefullname(path,name)
- if luaname then
- texio.write(string.format("(save: %s)",luaname))
- table.tofile(luaname,data,true,{ reduce = true })
- if lucname and type(caches.compile) == "function" then
- os.remove(lucname) -- better be safe
- texio.write(string.format("(save: %s)",lucname))
- caches.compile(data,luaname,lucname)
- end
- end
-end
-
--- According to KH os.execute is not permitted in plain/latex so there is
--- no reason to use the normal context way. So the method here is slightly
--- different from the one we have in context. We also use different suffixes
--- as we don't want any clashes (sharing cache files is not that handy as
--- context moves on faster.)
---
--- Beware: serialization might fail on large files (so maybe we should pcall
--- this) in which case one should limit the method to luac and enable support
--- for execution.
-
--- function caches.compile(data,luaname,lucname)
--- local d = io.loaddata(luaname)
--- if not d or d == "" then
--- d = table.serialize(data,true) -- slow
--- end
--- if d and d ~= "" then
--- local f = io.open(lucname,'w')
--- if f then
--- local s = loadstring(d)
--- if s then
--- f:write(string.dump(s,true))
--- end
--- f:close()
--- end
--- end
--- end
-
-function caches.compile(data,luaname,lucname)
- local d = io.loaddata(luaname)
- if not d or d == "" then
- d = table.serialize(data,true) -- slow
- end
- if d and d ~= "" then
- local f = io.open(lucname,'wb')
- if f then
- local s = loadstring(d)
- if s then
- f:write(string.dump(s,true))
- end
- f:close()
- end
- end
-end
-
---
-
-function table.setmetatableindex(t,f)
- setmetatable(t,{ __index = f })
-end
+if not modules then modules = { } end modules ['luat-basics-gen'] = { + version = 1.100, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local dummyfunction = function() +end + +local dummyreporter = function(c) + return function(...) + (texio.reporter or texio.write_nl)(c .. " : " .. string.formatters(...)) + end +end + +statistics = { + register = dummyfunction, + starttiming = dummyfunction, + stoptiming = dummyfunction, + elapsedtime = nil, +} + +directives = { + register = dummyfunction, + enable = dummyfunction, + disable = dummyfunction, +} + +trackers = { + register = dummyfunction, + enable = dummyfunction, + disable = dummyfunction, +} + +experiments = { + register = dummyfunction, + enable = dummyfunction, + disable = dummyfunction, +} + +storage = { -- probably no longer needed + register = dummyfunction, + shared = { }, +} + +logs = { + new = dummyreporter, + reporter = dummyreporter, + messenger = dummyreporter, + report = dummyfunction, +} + +callbacks = { + register = function(n,f) return callback.register(n,f) end, + +} + +utilities = { + storage = { + allocate = function(t) return t or { } end, + mark = function(t) return t or { } end, + }, +} + +characters = characters or { + data = { } +} + +-- we need to cheat a bit here + +texconfig.kpse_init = true + +resolvers = resolvers or { } -- no fancy file helpers used + +local remapper = { + otf = "opentype fonts", + ttf = "truetype fonts", + ttc = "truetype fonts", + dfont = "truetype fonts", -- "truetype dictionary", + cid = "cid maps", + cidmap = "cid maps", + fea = "font feature files", + pfa = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this! + pfb = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this! +} + +function resolvers.findfile(name,fileformat) + name = string.gsub(name,"\\","/") + if not fileformat or fileformat == "" then + fileformat = file.suffix(name) + if fileformat == "" then + fileformat = "tex" + end + end + fileformat = string.lower(fileformat) + fileformat = remapper[fileformat] or fileformat + local found = kpse.find_file(name,fileformat) + if not found or found == "" then + found = kpse.find_file(name,"other text files") + end + return found +end + +-- function resolvers.findbinfile(name,fileformat) +-- if not fileformat or fileformat == "" then +-- fileformat = file.suffix(name) +-- end +-- return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat) +-- end + +resolvers.findbinfile = resolvers.findfile + +function resolvers.resolve(s) + return s +end + +function resolvers.unresolve(s) + return s +end + +-- Caches ... I will make a real stupid version some day when I'm in the +-- mood. After all, the generic code does not need the more advanced +-- ConTeXt features. Cached data is not shared between ConTeXt and other +-- usage as I don't want any dependency at all. Also, ConTeXt might have +-- different needs and tricks added. + +--~ containers.usecache = true + +caches = { } + +local writable = nil +local readables = { } +local usingjit = jit + +if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then + caches.namespace = 'generic' +end + +do + + -- standard context tree setup + + local cachepaths = kpse.expand_path('$TEXMFCACHE') or "" + + -- quite like tex live or so + + if cachepaths == "" then + cachepaths = kpse.expand_path('$TEXMFVAR') + end + + -- this also happened to be used + + if cachepaths == "" then + cachepaths = kpse.expand_path('$VARTEXMF') + end + + -- and this is a last resort + + if cachepaths == "" then + cachepaths = "." + end + + cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":") + + for i=1,#cachepaths do + local cachepath = cachepaths[i] + if not lfs.isdir(cachepath) then + lfs.mkdirs(cachepath) -- needed for texlive and latex + if lfs.isdir(cachepath) then + texio.write(string.format("(created cache path: %s)",cachepath)) + end + end + if file.is_writable(cachepath) then + writable = file.join(cachepath,"luatex-cache") + lfs.mkdir(writable) + writable = file.join(writable,caches.namespace) + lfs.mkdir(writable) + break + end + end + + for i=1,#cachepaths do + if file.is_readable(cachepaths[i]) then + readables[#readables+1] = file.join(cachepaths[i],"luatex-cache",caches.namespace) + end + end + + if not writable then + texio.write_nl("quiting: fix your writable cache path") + os.exit() + elseif #readables == 0 then + texio.write_nl("quiting: fix your readable cache path") + os.exit() + elseif #readables == 1 and readables[1] == writable then + texio.write(string.format("(using cache: %s)",writable)) + else + texio.write(string.format("(using write cache: %s)",writable)) + texio.write(string.format("(using read cache: %s)",table.concat(readables, " "))) + end + +end + +function caches.getwritablepath(category,subcategory) + local path = file.join(writable,category) + lfs.mkdir(path) + path = file.join(path,subcategory) + lfs.mkdir(path) + return path +end + +function caches.getreadablepaths(category,subcategory) + local t = { } + for i=1,#readables do + t[i] = file.join(readables[i],category,subcategory) + end + return t +end + +local function makefullname(path,name) + if path and path ~= "" then + return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),usingjit and "lub" or "luc") + end +end + +function caches.is_writable(path,name) + local fullname = makefullname(path,name) + return fullname and file.is_writable(fullname) +end + +function caches.loaddata(paths,name) + for i=1,#paths do + local data = false + local luaname, lucname = makefullname(paths[i],name) + if lucname and lfs.isfile(lucname) then -- maybe also check for size + texio.write(string.format("(load luc: %s)",lucname)) + data = loadfile(lucname) + if data then + data = data() + end + if data then + return data + else + texio.write(string.format("(loading failed: %s)",lucname)) + end + end + if luaname and lfs.isfile(luaname) then + texio.write(string.format("(load lua: %s)",luaname)) + data = loadfile(luaname) + if data then + data = data() + end + if data then + return data + end + end + end +end + +function caches.savedata(path,name,data) + local luaname, lucname = makefullname(path,name) + if luaname then + texio.write(string.format("(save: %s)",luaname)) + table.tofile(luaname,data,true,{ reduce = true }) + if lucname and type(caches.compile) == "function" then + os.remove(lucname) -- better be safe + texio.write(string.format("(save: %s)",lucname)) + caches.compile(data,luaname,lucname) + end + end +end + +-- According to KH os.execute is not permitted in plain/latex so there is +-- no reason to use the normal context way. So the method here is slightly +-- different from the one we have in context. We also use different suffixes +-- as we don't want any clashes (sharing cache files is not that handy as +-- context moves on faster.) +-- +-- Beware: serialization might fail on large files (so maybe we should pcall +-- this) in which case one should limit the method to luac and enable support +-- for execution. + +-- function caches.compile(data,luaname,lucname) +-- local d = io.loaddata(luaname) +-- if not d or d == "" then +-- d = table.serialize(data,true) -- slow +-- end +-- if d and d ~= "" then +-- local f = io.open(lucname,'w') +-- if f then +-- local s = loadstring(d) +-- if s then +-- f:write(string.dump(s,true)) +-- end +-- f:close() +-- end +-- end +-- end + +function caches.compile(data,luaname,lucname) + local d = io.loaddata(luaname) + if not d or d == "" then + d = table.serialize(data,true) -- slow + end + if d and d ~= "" then + local f = io.open(lucname,'wb') + if f then + local s = loadstring(d) + if s then + f:write(string.dump(s,true)) + end + f:close() + end + end +end + +-- + +function table.setmetatableindex(t,f) + setmetatable(t,{ __index = f }) +end diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua index 38ccd8fc7..5ab9df7f9 100644 --- a/tex/generic/context/luatex/luatex-basics-nod.lua +++ b/tex/generic/context/luatex/luatex-basics-nod.lua @@ -1,104 +1,104 @@ -if not modules then modules = { } end modules ['luatex-fonts-nod'] = {
- version = 1.001,
- comment = "companion to luatex-fonts.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
--- Don't depend on code here as it is only needed to complement the
--- font handler code.
-
--- Attributes:
-
-if tex.attribute[0] ~= 0 then
-
- texio.write_nl("log","!")
- texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
- texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
- texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
- texio.write_nl("log","!")
-
- tex.attribute[0] = 0 -- else no features
-
-end
-
-attributes = attributes or { }
-attributes.unsetvalue = -0x7FFFFFFF
-
-local numbers, last = { }, 127
-
-attributes.private = attributes.private or function(name)
- local number = numbers[name]
- if not number then
- if last < 255 then
- last = last + 1
- end
- number = last
- numbers[name] = number
- end
- return number
-end
-
--- Nodes:
-
-nodes = { }
-nodes.pool = { }
-nodes.handlers = { }
-
-local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
-local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
-local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
-
-nodes.nodecodes = nodecodes
-nodes.whatcodes = whatcodes
-nodes.whatsitcodes = whatcodes
-nodes.glyphcodes = glyphcodes
-
-local free_node = node.free
-local remove_node = node.remove
-local new_node = node.new
-local traverse_id = node.traverse_id
-
-local math_code = nodecodes.math
-
-nodes.handlers.protectglyphs = node.protect_glyphs
-nodes.handlers.unprotectglyphs = node.unprotect_glyphs
-
-function nodes.remove(head, current, free_too)
- local t = current
- head, current = remove_node(head,current)
- if t then
- if free_too then
- free_node(t)
- t = nil
- else
- t.next, t.prev = nil, nil
- end
- end
- return head, current, t
-end
-
-function nodes.delete(head,current)
- return nodes.remove(head,current,true)
-end
-
-nodes.before = node.insert_before
-nodes.after = node.insert_after
-
-function nodes.pool.kern(k)
- local n = new_node("kern",1)
- n.kern = k
- return n
-end
-
-function nodes.endofmath(n)
- for n in traverse_id(math_code,n.next) do
- return n
- end
-end
+if not modules then modules = { } end modules ['luatex-fonts-nod'] = { + version = 1.001, + comment = "companion to luatex-fonts.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +-- Don't depend on code here as it is only needed to complement the +-- font handler code. + +-- Attributes: + +if tex.attribute[0] ~= 0 then + + texio.write_nl("log","!") + texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") + texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") + texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.") + texio.write_nl("log","!") + + tex.attribute[0] = 0 -- else no features + +end + +attributes = attributes or { } +attributes.unsetvalue = -0x7FFFFFFF + +local numbers, last = { }, 127 + +attributes.private = attributes.private or function(name) + local number = numbers[name] + if not number then + if last < 255 then + last = last + 1 + end + number = last + numbers[name] = number + end + return number +end + +-- Nodes: + +nodes = { } +nodes.pool = { } +nodes.handlers = { } + +local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end +local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end +local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" } + +nodes.nodecodes = nodecodes +nodes.whatcodes = whatcodes +nodes.whatsitcodes = whatcodes +nodes.glyphcodes = glyphcodes + +local free_node = node.free +local remove_node = node.remove +local new_node = node.new +local traverse_id = node.traverse_id + +local math_code = nodecodes.math + +nodes.handlers.protectglyphs = node.protect_glyphs +nodes.handlers.unprotectglyphs = node.unprotect_glyphs + +function nodes.remove(head, current, free_too) + local t = current + head, current = remove_node(head,current) + if t then + if free_too then + free_node(t) + t = nil + else + t.next, t.prev = nil, nil + end + end + return head, current, t +end + +function nodes.delete(head,current) + return nodes.remove(head,current,true) +end + +nodes.before = node.insert_before +nodes.after = node.insert_after + +function nodes.pool.kern(k) + local n = new_node("kern",1) + n.kern = k + return n +end + +function nodes.endofmath(n) + for n in traverse_id(math_code,n.next) do + return n + end +end diff --git a/tex/generic/context/luatex/luatex-fonts-cbk.lua b/tex/generic/context/luatex/luatex-fonts-cbk.lua index b4f4c8c91..9db94f65e 100644 --- a/tex/generic/context/luatex/luatex-fonts-cbk.lua +++ b/tex/generic/context/luatex/luatex-fonts-cbk.lua @@ -1,68 +1,68 @@ -if not modules then modules = { } end modules ['luatex-fonts-cbk'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-local nodes = nodes
-
--- Fonts: (might move to node-gef.lua)
-
-local traverse_id = node.traverse_id
-local glyph_code = nodes.nodecodes.glyph
-
-function nodes.handlers.characters(head)
- local fontdata = fonts.hashes.identifiers
- if fontdata then
- local usedfonts, done, prevfont = { }, false, nil
- for n in traverse_id(glyph_code,head) do
- local font = n.font
- if font ~= prevfont then
- prevfont = font
- local used = usedfonts[font]
- if not used then
- local tfmdata = fontdata[font] --
- if tfmdata then
- local shared = tfmdata.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processes
- if processors and #processors > 0 then
- usedfonts[font] = processors
- done = true
- end
- end
- end
- end
- end
- end
- if done then
- for font, processors in next, usedfonts do
- for i=1,#processors do
- local h, d = processors[i](head,font,0)
- head, done = h or head, done or d
- end
- end
- end
- return head, true
- else
- return head, false
- end
-end
-
-function nodes.simple_font_handler(head)
--- lang.hyphenate(head)
- head = nodes.handlers.characters(head)
- nodes.injections.handler(head)
- nodes.handlers.protectglyphs(head)
- head = node.ligaturing(head)
- head = node.kerning(head)
- return head
-end
+if not modules then modules = { } end modules ['luatex-fonts-cbk'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts +local nodes = nodes + +-- Fonts: (might move to node-gef.lua) + +local traverse_id = node.traverse_id +local glyph_code = nodes.nodecodes.glyph + +function nodes.handlers.characters(head) + local fontdata = fonts.hashes.identifiers + if fontdata then + local usedfonts, done, prevfont = { }, false, nil + for n in traverse_id(glyph_code,head) do + local font = n.font + if font ~= prevfont then + prevfont = font + local used = usedfonts[font] + if not used then + local tfmdata = fontdata[font] -- + if tfmdata then + local shared = tfmdata.shared -- we need to check shared, only when same features + if shared then + local processors = shared.processes + if processors and #processors > 0 then + usedfonts[font] = processors + done = true + end + end + end + end + end + end + if done then + for font, processors in next, usedfonts do + for i=1,#processors do + local h, d = processors[i](head,font,0) + head, done = h or head, done or d + end + end + end + return head, true + else + return head, false + end +end + +function nodes.simple_font_handler(head) +-- lang.hyphenate(head) + head = nodes.handlers.characters(head) + nodes.injections.handler(head) + nodes.handlers.protectglyphs(head) + head = node.ligaturing(head) + head = node.kerning(head) + return head +end diff --git a/tex/generic/context/luatex/luatex-fonts-def.lua b/tex/generic/context/luatex/luatex-fonts-def.lua index affe763c2..0c2f0dbd5 100644 --- a/tex/generic/context/luatex/luatex-fonts-def.lua +++ b/tex/generic/context/luatex/luatex-fonts-def.lua @@ -1,97 +1,97 @@ -if not modules then modules = { } end modules ['luatex-font-def'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-
--- A bit of tuning for definitions.
-
-fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
-
--- tricky: we sort of bypass the parser and directly feed all into
--- the sub parser
-
-function fonts.definers.getspecification(str)
- return "", str, "", ":", str
-end
-
--- the generic name parser (different from context!)
-
-local list = { }
-
-local function issome () list.lookup = 'name' end -- xetex mode prefers name (not in context!)
-local function isfile () list.lookup = 'file' end
-local function isname () list.lookup = 'name' end
-local function thename(s) list.name = s end
-local function issub (v) list.sub = v end
-local function iscrap (s) list.crap = string.lower(s) end
-local function iskey (k,v) list[k] = v end
-local function istrue (s) list[s] = true end
-local function isfalse(s) list[s] = false end
-
-local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
-
-local spaces = P(" ")^0
-local namespec = (1-S("/:("))^0 -- was: (1-S("/: ("))^0
-local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces
-local filename_1 = P("file:")/isfile * (namespec/thename)
-local filename_2 = P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]")
-local fontname_1 = P("name:")/isname * (namespec/thename)
-local fontname_2 = P(true)/issome * (namespec/thename)
-local sometext = (R("az","AZ","09") + S("+-."))^1
-local truevalue = P("+") * spaces * (sometext/istrue)
-local falsevalue = P("-") * spaces * (sometext/isfalse)
-local keyvalue = (C(sometext) * spaces * P("=") * spaces * C(sometext))/iskey
-local somevalue = sometext/istrue
-local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim
-local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
-local options = P(":") * spaces * (P(";")^0 * option)^0
-
-local pattern = (filename_1 + filename_2 + fontname_1 + fontname_2) * subvalue^0 * crapspec^0 * options^0
-
-local function colonized(specification) -- xetex mode
- list = { }
- lpeg.match(pattern,specification.specification)
- list.crap = nil -- style not supported, maybe some day
- if list.name then
- specification.name = list.name
- list.name = nil
- end
- if list.lookup then
- specification.lookup = list.lookup
- list.lookup = nil
- end
- if list.sub then
- specification.sub = list.sub
- list.sub = nil
- end
- specification.features.normal = fonts.handlers.otf.features.normalize(list)
- return specification
-end
-
-fonts.definers.registersplit(":",colonized,"cryptic")
-fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names]
-
-function fonts.definers.applypostprocessors(tfmdata)
- local postprocessors = tfmdata.postprocessors
- if postprocessors then
- for i=1,#postprocessors do
- local extrahash = postprocessors[i](tfmdata) -- after scaling etc
- if type(extrahash) == "string" and extrahash ~= "" then
- -- e.g. a reencoding needs this
- extrahash = string.gsub(lower(extrahash),"[^a-z]","-")
- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
- end
- end
- end
- return tfmdata
-end
+if not modules then modules = { } end modules ['luatex-font-def'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts + +-- A bit of tuning for definitions. + +fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload + +-- tricky: we sort of bypass the parser and directly feed all into +-- the sub parser + +function fonts.definers.getspecification(str) + return "", str, "", ":", str +end + +-- the generic name parser (different from context!) + +local list = { } + +local function issome () list.lookup = 'name' end -- xetex mode prefers name (not in context!) +local function isfile () list.lookup = 'file' end +local function isname () list.lookup = 'name' end +local function thename(s) list.name = s end +local function issub (v) list.sub = v end +local function iscrap (s) list.crap = string.lower(s) end +local function iskey (k,v) list[k] = v end +local function istrue (s) list[s] = true end +local function isfalse(s) list[s] = false end + +local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C + +local spaces = P(" ")^0 +local namespec = (1-S("/:("))^0 -- was: (1-S("/: ("))^0 +local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces +local filename_1 = P("file:")/isfile * (namespec/thename) +local filename_2 = P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]") +local fontname_1 = P("name:")/isname * (namespec/thename) +local fontname_2 = P(true)/issome * (namespec/thename) +local sometext = (R("az","AZ","09") + S("+-."))^1 +local truevalue = P("+") * spaces * (sometext/istrue) +local falsevalue = P("-") * spaces * (sometext/isfalse) +local keyvalue = (C(sometext) * spaces * P("=") * spaces * C(sometext))/iskey +local somevalue = sometext/istrue +local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim +local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces +local options = P(":") * spaces * (P(";")^0 * option)^0 + +local pattern = (filename_1 + filename_2 + fontname_1 + fontname_2) * subvalue^0 * crapspec^0 * options^0 + +local function colonized(specification) -- xetex mode + list = { } + lpeg.match(pattern,specification.specification) + list.crap = nil -- style not supported, maybe some day + if list.name then + specification.name = list.name + list.name = nil + end + if list.lookup then + specification.lookup = list.lookup + list.lookup = nil + end + if list.sub then + specification.sub = list.sub + list.sub = nil + end + specification.features.normal = fonts.handlers.otf.features.normalize(list) + return specification +end + +fonts.definers.registersplit(":",colonized,"cryptic") +fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names] + +function fonts.definers.applypostprocessors(tfmdata) + local postprocessors = tfmdata.postprocessors + if postprocessors then + for i=1,#postprocessors do + local extrahash = postprocessors[i](tfmdata) -- after scaling etc + if type(extrahash) == "string" and extrahash ~= "" then + -- e.g. a reencoding needs this + extrahash = string.gsub(lower(extrahash),"[^a-z]","-") + tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash) + end + end + end + return tfmdata +end diff --git a/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua b/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua index 6b622aa05..3878ae648 100644 --- a/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua +++ b/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua @@ -1,38 +1,38 @@ -local identifiers = fonts.hashes.identifiers
-
-return function(specification)
- local f1, id1 = fonts.constructors.readanddefine('lmroman10-regular', specification.size)
- local f2, id2 = fonts.constructors.readanddefine('lmsans10-regular', specification.size)
- local f3, id3 = fonts.constructors.readanddefine('lmtypewriter10-regular',specification.size)
- if f1 and f2 and f3 then
- f1.properties.name = specification.name
- f1.properties.virtualized = true
- f1.fonts = {
- { id = id1 },
- { id = id2 },
- { id = id3 },
- }
- local color = { [0] =
- { "special", "pdf:0 g" },
- { "special", "pdf:1 0 0 rg" },
- { "special", "pdf:0 1 0 rg" },
- { "special", "pdf:0 0 1 rg" },
- }
- local chars = {
- identifiers[id1].characters,
- identifiers[id2].characters,
- identifiers[id3].characters,
- }
- for u, v in next, f1.characters do
- local n = math.floor(math.random(1,3)+0.5)
- local c = chars[n][u] or v
- v.commands = { color[n], { 'slot', n, u }, color[0] }
- v.kerns = nil
- v.width = c.width
- v.height = c.height
- v.depth = c.depth
- v.italic = nil
- end
- end
- return f1
-end
+local identifiers = fonts.hashes.identifiers + +return function(specification) + local f1, id1 = fonts.constructors.readanddefine('lmroman10-regular', specification.size) + local f2, id2 = fonts.constructors.readanddefine('lmsans10-regular', specification.size) + local f3, id3 = fonts.constructors.readanddefine('lmtypewriter10-regular',specification.size) + if f1 and f2 and f3 then + f1.properties.name = specification.name + f1.properties.virtualized = true + f1.fonts = { + { id = id1 }, + { id = id2 }, + { id = id3 }, + } + local color = { [0] = + { "special", "pdf:0 g" }, + { "special", "pdf:1 0 0 rg" }, + { "special", "pdf:0 1 0 rg" }, + { "special", "pdf:0 0 1 rg" }, + } + local chars = { + identifiers[id1].characters, + identifiers[id2].characters, + identifiers[id3].characters, + } + for u, v in next, f1.characters do + local n = math.floor(math.random(1,3)+0.5) + local c = chars[n][u] or v + v.commands = { color[n], { 'slot', n, u }, color[0] } + v.kerns = nil + v.width = c.width + v.height = c.height + v.depth = c.depth + v.italic = nil + end + end + return f1 +end diff --git a/tex/generic/context/luatex/luatex-fonts-enc.lua b/tex/generic/context/luatex/luatex-fonts-enc.lua index 03f68118b..e20c3a03b 100644 --- a/tex/generic/context/luatex/luatex-fonts-enc.lua +++ b/tex/generic/context/luatex/luatex-fonts-enc.lua @@ -1,28 +1,28 @@ -if not modules then modules = { } end modules ['luatex-font-enc'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-fonts.encodings = { }
-fonts.encodings.agl = { }
-
-setmetatable(fonts.encodings.agl, { __index = function(t,k)
- if k == "unicodes" then
- texio.write(" <loading (extended) adobe glyph list>")
- local unicodes = dofile(resolvers.findfile("font-age.lua"))
- fonts.encodings.agl = { unicodes = unicodes }
- return unicodes
- else
- return nil
- end
-end })
-
+if not modules then modules = { } end modules ['luatex-font-enc'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts +fonts.encodings = { } +fonts.encodings.agl = { } + +setmetatable(fonts.encodings.agl, { __index = function(t,k) + if k == "unicodes" then + texio.write(" <loading (extended) adobe glyph list>") + local unicodes = dofile(resolvers.findfile("font-age.lua")) + fonts.encodings.agl = { unicodes = unicodes } + return unicodes + else + return nil + end +end }) + diff --git a/tex/generic/context/luatex/luatex-fonts-ext.lua b/tex/generic/context/luatex/luatex-fonts-ext.lua index 63927c035..b60d04512 100644 --- a/tex/generic/context/luatex/luatex-fonts-ext.lua +++ b/tex/generic/context/luatex/luatex-fonts-ext.lua @@ -1,272 +1,272 @@ -if not modules then modules = { } end modules ['luatex-fonts-ext'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-local otffeatures = fonts.constructors.newfeatures("otf")
-
--- A few generic extensions.
-
-local function initializeitlc(tfmdata,value)
- if value then
- -- the magic 40 and it formula come from Dohyun Kim but we might need another guess
- local parameters = tfmdata.parameters
- local italicangle = parameters.italicangle
- if italicangle and italicangle ~= 0 then
- local properties = tfmdata.properties
- local factor = tonumber(value) or 1
- properties.hasitalics = true
- properties.autoitalicamount = factor * (parameters.uwidth or 40)/2
- end
- end
-end
-
-otffeatures.register {
- name = "itlc",
- description = "italic correction",
- initializers = {
- base = initializeitlc,
- node = initializeitlc,
- }
-}
-
--- slant and extend
-
-local function initializeslant(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 1 then
- value = 1
- elseif value < -1 then
- value = -1
- end
- tfmdata.parameters.slantfactor = value
-end
-
-otffeatures.register {
- name = "slant",
- description = "slant glyphs",
- initializers = {
- base = initializeslant,
- node = initializeslant,
- }
-}
-
-local function initializeextend(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 10 then
- value = 10
- elseif value < -10 then
- value = -10
- end
- tfmdata.parameters.extendfactor = value
-end
-
-otffeatures.register {
- name = "extend",
- description = "scale glyphs horizontally",
- initializers = {
- base = initializeextend,
- node = initializeextend,
- }
-}
-
--- expansion and protrusion
-
-fonts.protrusions = fonts.protrusions or { }
-fonts.protrusions.setups = fonts.protrusions.setups or { }
-
-local setups = fonts.protrusions.setups
-
-local function initializeprotrusion(tfmdata,value)
- if value then
- local setup = setups[value]
- if setup then
- local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1
- local emwidth = tfmdata.parameters.quad
- tfmdata.parameters.protrusion = {
- auto = true,
- }
- for i, chr in next, tfmdata.characters do
- local v, pl, pr = setup[i], nil, nil
- if v then
- pl, pr = v[1], v[2]
- end
- if pl and pl ~= 0 then chr.left_protruding = left *pl*factor end
- if pr and pr ~= 0 then chr.right_protruding = right*pr*factor end
- end
- end
- end
-end
-
-otffeatures.register {
- name = "protrusion",
- description = "shift characters into the left and or right margin",
- initializers = {
- base = initializeprotrusion,
- node = initializeprotrusion,
- }
-}
-
-fonts.expansions = fonts.expansions or { }
-fonts.expansions.setups = fonts.expansions.setups or { }
-
-local setups = fonts.expansions.setups
-
-local function initializeexpansion(tfmdata,value)
- if value then
- local setup = setups[value]
- if setup then
- local factor = setup.factor or 1
- tfmdata.parameters.expansion = {
- stretch = 10 * (setup.stretch or 0),
- shrink = 10 * (setup.shrink or 0),
- step = 10 * (setup.step or 0),
- auto = true,
- }
- for i, chr in next, tfmdata.characters do
- local v = setup[i]
- if v and v ~= 0 then
- chr.expansion_factor = v*factor
- else -- can be option
- chr.expansion_factor = factor
- end
- end
- end
- end
-end
-
-otffeatures.register {
- name = "expansion",
- description = "apply hz optimization",
- initializers = {
- base = initializeexpansion,
- node = initializeexpansion,
- }
-}
-
--- left over
-
-function fonts.loggers.onetimemessage() end
-
--- example vectors
-
-local byte = string.byte
-
-fonts.expansions.setups['default'] = {
-
- stretch = 2, shrink = 2, step = .5, factor = 1,
-
- [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
- [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
- [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
- [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
- [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
- [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
- [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
- [byte('w')] = 0.7, [byte('z')] = 0.7,
- [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
-}
-
-fonts.protrusions.setups['default'] = {
-
- factor = 1, left = 1, right = 1,
-
- [0x002C] = { 0, 1 }, -- comma
- [0x002E] = { 0, 1 }, -- period
- [0x003A] = { 0, 1 }, -- colon
- [0x003B] = { 0, 1 }, -- semicolon
- [0x002D] = { 0, 1 }, -- hyphen
- [0x2013] = { 0, 0.50 }, -- endash
- [0x2014] = { 0, 0.33 }, -- emdash
- [0x3001] = { 0, 1 }, -- ideographic comma 、
- [0x3002] = { 0, 1 }, -- ideographic full stop 。
- [0x060C] = { 0, 1 }, -- arabic comma ،
- [0x061B] = { 0, 1 }, -- arabic semicolon ؛
- [0x06D4] = { 0, 1 }, -- arabic full stop ۔
-
-}
-
--- normalizer
-
-fonts.handlers.otf.features.normalize = function(t)
- if t.rand then
- t.rand = "random"
- end
- return t
-end
-
--- bonus
-
-function fonts.helpers.nametoslot(name)
- local t = type(name)
- if t == "string" then
- local tfmdata = fonts.hashes.identifiers[currentfont()]
- local shared = tfmdata and tfmdata.shared
- local fntdata = shared and shared.rawdata
- return fntdata and fntdata.resources.unicodes[name]
- elseif t == "number" then
- return n
- end
-end
-
--- \font\test=file:somefont:reencode=mymessup
---
--- fonts.encodings.reencodings.mymessup = {
--- [109] = 110, -- m
--- [110] = 109, -- n
--- }
-
-fonts.encodings = fonts.encodings or { }
-local reencodings = { }
-fonts.encodings.reencodings = reencodings
-
-local function specialreencode(tfmdata,value)
- -- we forget about kerns as we assume symbols and we
- -- could issue a message if ther are kerns but it's
- -- a hack anyway so we odn't care too much here
- local encoding = value and reencodings[value]
- if encoding then
- local temp = { }
- local char = tfmdata.characters
- for k, v in next, encoding do
- temp[k] = char[v]
- end
- for k, v in next, temp do
- char[k] = temp[k]
- end
- -- if we use the font otherwise luatex gets confused so
- -- we return an additional hash component for fullname
- return string.format("reencoded:%s",value)
- end
-end
-
-local function reencode(tfmdata,value)
- tfmdata.postprocessors = tfmdata.postprocessors or { }
- table.insert(tfmdata.postprocessors,
- function(tfmdata)
- return specialreencode(tfmdata,value)
- end
- )
-end
-
-otffeatures.register {
- name = "reencode",
- description = "reencode characters",
- manipulators = {
- base = reencode,
- node = reencode,
- }
-}
+if not modules then modules = { } end modules ['luatex-fonts-ext'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts +local otffeatures = fonts.constructors.newfeatures("otf") + +-- A few generic extensions. + +local function initializeitlc(tfmdata,value) + if value then + -- the magic 40 and it formula come from Dohyun Kim but we might need another guess + local parameters = tfmdata.parameters + local italicangle = parameters.italicangle + if italicangle and italicangle ~= 0 then + local properties = tfmdata.properties + local factor = tonumber(value) or 1 + properties.hasitalics = true + properties.autoitalicamount = factor * (parameters.uwidth or 40)/2 + end + end +end + +otffeatures.register { + name = "itlc", + description = "italic correction", + initializers = { + base = initializeitlc, + node = initializeitlc, + } +} + +-- slant and extend + +local function initializeslant(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + elseif value > 1 then + value = 1 + elseif value < -1 then + value = -1 + end + tfmdata.parameters.slantfactor = value +end + +otffeatures.register { + name = "slant", + description = "slant glyphs", + initializers = { + base = initializeslant, + node = initializeslant, + } +} + +local function initializeextend(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + elseif value > 10 then + value = 10 + elseif value < -10 then + value = -10 + end + tfmdata.parameters.extendfactor = value +end + +otffeatures.register { + name = "extend", + description = "scale glyphs horizontally", + initializers = { + base = initializeextend, + node = initializeextend, + } +} + +-- expansion and protrusion + +fonts.protrusions = fonts.protrusions or { } +fonts.protrusions.setups = fonts.protrusions.setups or { } + +local setups = fonts.protrusions.setups + +local function initializeprotrusion(tfmdata,value) + if value then + local setup = setups[value] + if setup then + local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1 + local emwidth = tfmdata.parameters.quad + tfmdata.parameters.protrusion = { + auto = true, + } + for i, chr in next, tfmdata.characters do + local v, pl, pr = setup[i], nil, nil + if v then + pl, pr = v[1], v[2] + end + if pl and pl ~= 0 then chr.left_protruding = left *pl*factor end + if pr and pr ~= 0 then chr.right_protruding = right*pr*factor end + end + end + end +end + +otffeatures.register { + name = "protrusion", + description = "shift characters into the left and or right margin", + initializers = { + base = initializeprotrusion, + node = initializeprotrusion, + } +} + +fonts.expansions = fonts.expansions or { } +fonts.expansions.setups = fonts.expansions.setups or { } + +local setups = fonts.expansions.setups + +local function initializeexpansion(tfmdata,value) + if value then + local setup = setups[value] + if setup then + local factor = setup.factor or 1 + tfmdata.parameters.expansion = { + stretch = 10 * (setup.stretch or 0), + shrink = 10 * (setup.shrink or 0), + step = 10 * (setup.step or 0), + auto = true, + } + for i, chr in next, tfmdata.characters do + local v = setup[i] + if v and v ~= 0 then + chr.expansion_factor = v*factor + else -- can be option + chr.expansion_factor = factor + end + end + end + end +end + +otffeatures.register { + name = "expansion", + description = "apply hz optimization", + initializers = { + base = initializeexpansion, + node = initializeexpansion, + } +} + +-- left over + +function fonts.loggers.onetimemessage() end + +-- example vectors + +local byte = string.byte + +fonts.expansions.setups['default'] = { + + stretch = 2, shrink = 2, step = .5, factor = 1, + + [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7, + [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7, + [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7, + [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7, + [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7, + [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7, + [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7, + [byte('w')] = 0.7, [byte('z')] = 0.7, + [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7, +} + +fonts.protrusions.setups['default'] = { + + factor = 1, left = 1, right = 1, + + [0x002C] = { 0, 1 }, -- comma + [0x002E] = { 0, 1 }, -- period + [0x003A] = { 0, 1 }, -- colon + [0x003B] = { 0, 1 }, -- semicolon + [0x002D] = { 0, 1 }, -- hyphen + [0x2013] = { 0, 0.50 }, -- endash + [0x2014] = { 0, 0.33 }, -- emdash + [0x3001] = { 0, 1 }, -- ideographic comma 、 + [0x3002] = { 0, 1 }, -- ideographic full stop 。 + [0x060C] = { 0, 1 }, -- arabic comma ، + [0x061B] = { 0, 1 }, -- arabic semicolon ؛ + [0x06D4] = { 0, 1 }, -- arabic full stop ۔ + +} + +-- normalizer + +fonts.handlers.otf.features.normalize = function(t) + if t.rand then + t.rand = "random" + end + return t +end + +-- bonus + +function fonts.helpers.nametoslot(name) + local t = type(name) + if t == "string" then + local tfmdata = fonts.hashes.identifiers[currentfont()] + local shared = tfmdata and tfmdata.shared + local fntdata = shared and shared.rawdata + return fntdata and fntdata.resources.unicodes[name] + elseif t == "number" then + return n + end +end + +-- \font\test=file:somefont:reencode=mymessup +-- +-- fonts.encodings.reencodings.mymessup = { +-- [109] = 110, -- m +-- [110] = 109, -- n +-- } + +fonts.encodings = fonts.encodings or { } +local reencodings = { } +fonts.encodings.reencodings = reencodings + +local function specialreencode(tfmdata,value) + -- we forget about kerns as we assume symbols and we + -- could issue a message if ther are kerns but it's + -- a hack anyway so we odn't care too much here + local encoding = value and reencodings[value] + if encoding then + local temp = { } + local char = tfmdata.characters + for k, v in next, encoding do + temp[k] = char[v] + end + for k, v in next, temp do + char[k] = temp[k] + end + -- if we use the font otherwise luatex gets confused so + -- we return an additional hash component for fullname + return string.format("reencoded:%s",value) + end +end + +local function reencode(tfmdata,value) + tfmdata.postprocessors = tfmdata.postprocessors or { } + table.insert(tfmdata.postprocessors, + function(tfmdata) + return specialreencode(tfmdata,value) + end + ) +end + +otffeatures.register { + name = "reencode", + description = "reencode characters", + manipulators = { + base = reencode, + node = reencode, + } +} diff --git a/tex/generic/context/luatex/luatex-fonts-lua.lua b/tex/generic/context/luatex/luatex-fonts-lua.lua index 9aa45fd22..ec3fe38be 100644 --- a/tex/generic/context/luatex/luatex-fonts-lua.lua +++ b/tex/generic/context/luatex/luatex-fonts-lua.lua @@ -1,33 +1,33 @@ -if not modules then modules = { } end modules ['luatex-fonts-lua'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-fonts.formats.lua = "lua"
-
-function fonts.readers.lua(specification)
- local fullname = specification.filename or ""
- if fullname == "" then
- local forced = specification.forced or ""
- if forced ~= "" then
- fullname = specification.name .. "." .. forced
- else
- fullname = specification.name
- end
- end
- local fullname = resolvers.findfile(fullname) or ""
- if fullname ~= "" then
- local loader = loadfile(fullname)
- loader = loader and loader()
- return loader and loader(specification)
- end
-end
+if not modules then modules = { } end modules ['luatex-fonts-lua'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts +fonts.formats.lua = "lua" + +function fonts.readers.lua(specification) + local fullname = specification.filename or "" + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + fullname = specification.name .. "." .. forced + else + fullname = specification.name + end + end + local fullname = resolvers.findfile(fullname) or "" + if fullname ~= "" then + local loader = loadfile(fullname) + loader = loader and loader() + return loader and loader(specification) + end +end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index c8923a436..71f6e79a4 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,49 +1,49 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 05/19/13 19:27:29 +-- merge date : 05/20/13 02:00:30 do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-lua']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-lua']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local major,minor=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") -_MAJORVERSION=tonumber(major) or 5
-_MINORVERSION=tonumber(minor) or 1
+_MAJORVERSION=tonumber(major) or 5 +_MINORVERSION=tonumber(minor) or 1 _LUAVERSION=_MAJORVERSION+_MINORVERSION/10 -if not lpeg then
- lpeg=require("lpeg")
+if not lpeg then + lpeg=require("lpeg") end if loadstring then local loadnormal=load - function load(first,...)
- if type(first)=="string" then
- return loadstring(first,...)
- else
- return loadnormal(first,...)
- end
+ function load(first,...) + if type(first)=="string" then + return loadstring(first,...) + else + return loadnormal(first,...) + end end else loadstring=load end if not ipairs then - local function iterate(a,i)
- i=i+1
- local v=a[i]
- if v~=nil then
+ local function iterate(a,i) + i=i+1 + local v=a[i] + if v~=nil then return i,v - end
+ end end - function ipairs(a)
- return iterate,a,0
+ function ipairs(a) + return iterate,a,0 end end if not pairs then - function pairs(t)
+ function pairs(t) return next,t end end @@ -58,602 +58,602 @@ end local print,select,tostring=print,select,tostring local inspectors={} function setinspector(inspector) - inspectors[#inspectors+1]=inspector
+ inspectors[#inspectors+1]=inspector end function inspect(...) - for s=1,select("#",...) do
- local value=select(s,...)
- local done=false
- for i=1,#inspectors do
- done=inspectors[i](value)
- if done then
- break
- end
- end
- if not done then
- print(tostring(value))
- end
- end
+ for s=1,select("#",...) do + local value=select(s,...) + local done=false + for i=1,#inspectors do + done=inspectors[i](value) + if done then + break + end + end + if not done then + print(tostring(value)) + end + end end local dummy=function() end -function optionalrequire(...)
- local ok,result=xpcall(require,dummy,...)
- if ok then
- return result
- end
-end
+function optionalrequire(...) + local ok,result=xpcall(require,dummy,...) + if ok then + return result + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-lpeg']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-lpeg']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } lpeg=require("lpeg") -local type,next,tostring=type,next,tostring
+local type,next,tostring=type,next,tostring local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format local floor=math.floor -local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
+local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns -local anything=P(1)
-local endofstring=P(-1)
+local anything=P(1) +local endofstring=P(-1) local alwaysmatched=P(true) -patterns.anything=anything
-patterns.endofstring=endofstring
-patterns.beginofstring=alwaysmatched
+patterns.anything=anything +patterns.endofstring=endofstring +patterns.beginofstring=alwaysmatched patterns.alwaysmatched=alwaysmatched -local digit,sign=R('09'),S('+-')
-local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
+local digit,sign=R('09'),S('+-') +local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") local newline=crlf+S("\r\n") -local escaped=P("\\")*anything
-local squote=P("'")
-local dquote=P('"')
+local escaped=P("\\")*anything +local squote=P("'") +local dquote=P('"') local space=P(" ") -local utfbom_32_be=P('\000\000\254\255')
-local utfbom_32_le=P('\255\254\000\000')
-local utfbom_16_be=P('\255\254')
-local utfbom_16_le=P('\254\255')
-local utfbom_8=P('\239\187\191')
-local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
+local utfbom_32_be=P('\000\000\254\255') +local utfbom_32_le=P('\255\254\000\000') +local utfbom_16_be=P('\255\254') +local utfbom_16_le=P('\254\255') +local utfbom_8=P('\239\187\191') +local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8 local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0) local utf8next=R("\128\191") -patterns.utf8one=R("\000\127")
-patterns.utf8two=R("\194\223")*utf8next
-patterns.utf8three=R("\224\239")*utf8next*utf8next
-patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
-patterns.utfbom=utfbom
-patterns.utftype=utftype
+patterns.utf8one=R("\000\127") +patterns.utf8two=R("\194\223")*utf8next +patterns.utf8three=R("\224\239")*utf8next*utf8next +patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next +patterns.utfbom=utfbom +patterns.utftype=utftype patterns.utfoffset=utfoffset -local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
+local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false) local utf8character=P(1)*R("\128\191")^0 -patterns.utf8=utf8char
-patterns.utf8char=utf8char
+patterns.utf8=utf8char +patterns.utf8char=utf8char patterns.utf8character=utf8character -patterns.validutf8=validutf8char
+patterns.validutf8=validutf8char patterns.validutf8char=validutf8char -local eol=S("\n\r")
+local eol=S("\n\r") local spacer=S(" \t\f\v") -local whitespace=eol+spacer
-local nonspacer=1-spacer
+local whitespace=eol+spacer +local nonspacer=1-spacer local nonwhitespace=1-whitespace -patterns.eol=eol
-patterns.spacer=spacer
-patterns.whitespace=whitespace
-patterns.nonspacer=nonspacer
+patterns.eol=eol +patterns.spacer=spacer +patterns.whitespace=whitespace +patterns.nonspacer=nonspacer patterns.nonwhitespace=nonwhitespace local stripper=spacer^0*C((spacer^0*nonspacer^1)^0) local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0)) -patterns.stripper=stripper
+patterns.stripper=stripper patterns.collapser=collapser -patterns.digit=digit
-patterns.sign=sign
-patterns.cardinal=sign^0*digit^1
-patterns.integer=sign^0*digit^1
-patterns.unsigned=digit^0*P('.')*digit^1
-patterns.float=sign^0*patterns.unsigned
-patterns.cunsigned=digit^0*P(',')*digit^1
-patterns.cfloat=sign^0*patterns.cunsigned
-patterns.number=patterns.float+patterns.integer
-patterns.cnumber=patterns.cfloat+patterns.integer
-patterns.oct=P("0")*R("07")^1
-patterns.octal=patterns.oct
-patterns.HEX=P("0x")*R("09","AF")^1
-patterns.hex=P("0x")*R("09","af")^1
-patterns.hexadecimal=P("0x")*R("09","AF","af")^1
-patterns.lowercase=R("az")
-patterns.uppercase=R("AZ")
-patterns.letter=patterns.lowercase+patterns.uppercase
-patterns.space=space
-patterns.tab=P("\t")
-patterns.spaceortab=patterns.space+patterns.tab
-patterns.newline=newline
-patterns.emptyline=newline^1
-patterns.equal=P("=")
-patterns.comma=P(",")
-patterns.commaspacer=P(",")*spacer^0
-patterns.period=P(".")
-patterns.colon=P(":")
-patterns.semicolon=P(";")
-patterns.underscore=P("_")
-patterns.escaped=escaped
-patterns.squote=squote
-patterns.dquote=dquote
-patterns.nosquote=(escaped+(1-squote))^0
-patterns.nodquote=(escaped+(1-dquote))^0
+patterns.digit=digit +patterns.sign=sign +patterns.cardinal=sign^0*digit^1 +patterns.integer=sign^0*digit^1 +patterns.unsigned=digit^0*P('.')*digit^1 +patterns.float=sign^0*patterns.unsigned +patterns.cunsigned=digit^0*P(',')*digit^1 +patterns.cfloat=sign^0*patterns.cunsigned +patterns.number=patterns.float+patterns.integer +patterns.cnumber=patterns.cfloat+patterns.integer +patterns.oct=P("0")*R("07")^1 +patterns.octal=patterns.oct +patterns.HEX=P("0x")*R("09","AF")^1 +patterns.hex=P("0x")*R("09","af")^1 +patterns.hexadecimal=P("0x")*R("09","AF","af")^1 +patterns.lowercase=R("az") +patterns.uppercase=R("AZ") +patterns.letter=patterns.lowercase+patterns.uppercase +patterns.space=space +patterns.tab=P("\t") +patterns.spaceortab=patterns.space+patterns.tab +patterns.newline=newline +patterns.emptyline=newline^1 +patterns.equal=P("=") +patterns.comma=P(",") +patterns.commaspacer=P(",")*spacer^0 +patterns.period=P(".") +patterns.colon=P(":") +patterns.semicolon=P(";") +patterns.underscore=P("_") +patterns.escaped=escaped +patterns.squote=squote +patterns.dquote=dquote +patterns.nosquote=(escaped+(1-squote))^0 +patterns.nodquote=(escaped+(1-dquote))^0 patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"") patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"") patterns.unquoted=patterns.undouble+patterns.unsingle patterns.unspacer=((patterns.spacer^1)/"")^0 -patterns.singlequoted=squote*patterns.nosquote*squote
-patterns.doublequoted=dquote*patterns.nodquote*dquote
+patterns.singlequoted=squote*patterns.nosquote*squote +patterns.doublequoted=dquote*patterns.nodquote*dquote patterns.quoted=patterns.doublequoted+patterns.singlequoted patterns.propername=R("AZ","az","__")*R("09","AZ","az","__")^0*P(-1) patterns.somecontent=(anything-newline-space)^1 patterns.beginline=#(1-newline) patterns.longtostring=Cs(whitespace^0/""*nonwhitespace^0*((whitespace^0/" "*(patterns.quoted+nonwhitespace)^1)^0)) local function anywhere(pattern) - return P { P(pattern)+1*V(1) }
+ return P { P(pattern)+1*V(1) } end lpeg.anywhere=anywhere -function lpeg.instringchecker(p)
- p=anywhere(p)
- return function(str)
- return lpegmatch(p,str) and true or false
- end
+function lpeg.instringchecker(p) + p=anywhere(p) + return function(str) + return lpegmatch(p,str) and true or false + end end -function lpeg.splitter(pattern,action)
- return (((1-P(pattern))^1)/action+1)^0
+function lpeg.splitter(pattern,action) + return (((1-P(pattern))^1)/action+1)^0 end -function lpeg.tsplitter(pattern,action)
- return Ct((((1-P(pattern))^1)/action+1)^0)
+function lpeg.tsplitter(pattern,action) + return Ct((((1-P(pattern))^1)/action+1)^0) end local splitters_s,splitters_m,splitters_t={},{},{} -local function splitat(separator,single)
- local splitter=(single and splitters_s[separator]) or splitters_m[separator]
- if not splitter then
- separator=P(separator)
- local other=C((1-separator)^0)
- if single then
- local any=anything
+local function splitat(separator,single) + local splitter=(single and splitters_s[separator]) or splitters_m[separator] + if not splitter then + separator=P(separator) + local other=C((1-separator)^0) + if single then + local any=anything splitter=other*(separator*C(any^0)+"") - splitters_s[separator]=splitter
- else
- splitter=other*(separator*other)^0
- splitters_m[separator]=splitter
- end
- end
- return splitter
-end -local function tsplitat(separator)
- local splitter=splitters_t[separator]
- if not splitter then
- splitter=Ct(splitat(separator))
- splitters_t[separator]=splitter
- end
- return splitter
-end -lpeg.splitat=splitat
+ splitters_s[separator]=splitter + else + splitter=other*(separator*other)^0 + splitters_m[separator]=splitter + end + end + return splitter +end +local function tsplitat(separator) + local splitter=splitters_t[separator] + if not splitter then + splitter=Ct(splitat(separator)) + splitters_t[separator]=splitter + end + return splitter +end +lpeg.splitat=splitat lpeg.tsplitat=tsplitat -function string.splitup(str,separator)
- if not separator then
- separator=","
- end
- return lpegmatch(splitters_m[separator] or splitat(separator),str)
+function string.splitup(str,separator) + if not separator then + separator="," + end + return lpegmatch(splitters_m[separator] or splitat(separator),str) end local cache={} -function lpeg.split(separator,str)
- local c=cache[separator]
- if not c then
- c=tsplitat(separator)
- cache[separator]=c
- end
- return lpegmatch(c,str)
-end -function string.split(str,separator)
- if separator then
- local c=cache[separator]
- if not c then
- c=tsplitat(separator)
- cache[separator]=c
- end
- return lpegmatch(c,str)
- else
- return { str }
- end
+function lpeg.split(separator,str) + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.split(str,separator) + if separator then + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) + else + return { str } + end end local spacing=patterns.spacer^0*newline -local empty=spacing*Cc("")
-local nonempty=Cs((1-spacing)^1)*spacing^-1
+local empty=spacing*Cc("") +local nonempty=Cs((1-spacing)^1)*spacing^-1 local content=(empty+nonempty)^1 patterns.textline=content local linesplitter=tsplitat(newline) patterns.linesplitter=linesplitter -function string.splitlines(str)
- return lpegmatch(linesplitter,str)
+function string.splitlines(str) + return lpegmatch(linesplitter,str) end local cache={} -function lpeg.checkedsplit(separator,str)
- local c=cache[separator]
- if not c then
- separator=P(separator)
- local other=C((1-separator)^1)
- c=Ct(separator^0*other*(separator^1*other)^0)
- cache[separator]=c
- end
- return lpegmatch(c,str)
-end -function string.checkedsplit(str,separator)
- local c=cache[separator]
- if not c then
- separator=P(separator)
- local other=C((1-separator)^1)
- c=Ct(separator^0*other*(separator^1*other)^0)
- cache[separator]=c
- end
- return lpegmatch(c,str)
-end -local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end
-local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end
+function lpeg.checkedsplit(separator,str) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.checkedsplit(str,separator) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end +local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4 patterns.utf8byte=utf8byte local cache={} -function lpeg.stripper(str)
- if type(str)=="string" then
- local s=cache[str]
- if not s then
- s=Cs(((S(str)^1)/""+1)^0)
- cache[str]=s
- end
- return s
- else
- return Cs(((str^1)/""+1)^0)
- end
+function lpeg.stripper(str) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs(((S(str)^1)/""+1)^0) + cache[str]=s + end + return s + else + return Cs(((str^1)/""+1)^0) + end end local cache={} -function lpeg.keeper(str)
- if type(str)=="string" then
- local s=cache[str]
- if not s then
- s=Cs((((1-S(str))^1)/""+1)^0)
- cache[str]=s
- end
- return s
- else
- return Cs((((1-str)^1)/""+1)^0)
- end
+function lpeg.keeper(str) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs((((1-S(str))^1)/""+1)^0) + cache[str]=s + end + return s + else + return Cs((((1-str)^1)/""+1)^0) + end end function lpeg.frontstripper(str) - return (P(str)+P(true))*Cs(anything^0)
+ return (P(str)+P(true))*Cs(anything^0) end function lpeg.endstripper(str) - return Cs((1-P(str)*endofstring)^0)
+ return Cs((1-P(str)*endofstring)^0) end function lpeg.replacer(one,two,makefunction,isutf) - local pattern
- local u=isutf and utf8char or 1
- if type(one)=="table" then
- local no=#one
- local p=P(false)
- if no==0 then
- for k,v in next,one do
- p=p+P(k)/v
- end
- pattern=Cs((p+u)^0)
- elseif no==1 then
- local o=one[1]
+ local pattern + local u=isutf and utf8char or 1 + if type(one)=="table" then + local no=#one + local p=P(false) + if no==0 then + for k,v in next,one do + p=p+P(k)/v + end + pattern=Cs((p+u)^0) + elseif no==1 then + local o=one[1] one,two=P(o[1]),o[2] - pattern=Cs((one/two+u)^0)
- else
- for i=1,no do
- local o=one[i]
- p=p+P(o[1])/o[2]
- end
- pattern=Cs((p+u)^0)
- end
- else
- pattern=Cs((P(one)/(two or "")+u)^0)
- end
- if makefunction then
- return function(str)
- return lpegmatch(pattern,str)
- end
- else
- return pattern
- end
-end -function lpeg.finder(lst,makefunction)
- local pattern
- if type(lst)=="table" then
- pattern=P(false)
- if #lst==0 then
- for k,v in next,lst do
+ pattern=Cs((one/two+u)^0) + else + for i=1,no do + local o=one[i] + p=p+P(o[1])/o[2] + end + pattern=Cs((p+u)^0) + end + else + pattern=Cs((P(one)/(two or "")+u)^0) + end + if makefunction then + return function(str) + return lpegmatch(pattern,str) + end + else + return pattern + end +end +function lpeg.finder(lst,makefunction) + local pattern + if type(lst)=="table" then + pattern=P(false) + if #lst==0 then + for k,v in next,lst do pattern=pattern+P(k) - end
- else
- for i=1,#lst do
- pattern=pattern+P(lst[i])
- end
- end
- else
- pattern=P(lst)
- end
- pattern=(1-pattern)^0*pattern
- if makefunction then
- return function(str)
- return lpegmatch(pattern,str)
- end
- else
- return pattern
- end
+ end + else + for i=1,#lst do + pattern=pattern+P(lst[i]) + end + end + else + pattern=P(lst) + end + pattern=(1-pattern)^0*pattern + if makefunction then + return function(str) + return lpegmatch(pattern,str) + end + else + return pattern + end end local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) - local splitter=splitters_f[separator]
- if not splitter then
- separator=P(separator)
- splitter=C((1-separator)^0)
- splitters_f[separator]=splitter
- end
- return splitter
+ local splitter=splitters_f[separator] + if not splitter then + separator=P(separator) + splitter=C((1-separator)^0) + splitters_f[separator]=splitter + end + return splitter end function lpeg.secondofsplit(separator) - local splitter=splitters_s[separator]
- if not splitter then
- separator=P(separator)
- splitter=(1-separator)^0*separator*C(anything^0)
- splitters_s[separator]=splitter
- end
- return splitter
-end -function lpeg.balancer(left,right)
- left,right=P(left),P(right)
- return P { left*((1-left-right)+V(1))^0*right }
+ local splitter=splitters_s[separator] + if not splitter then + separator=P(separator) + splitter=(1-separator)^0*separator*C(anything^0) + splitters_s[separator]=splitter + end + return splitter +end +function lpeg.balancer(left,right) + left,right=P(left),P(right) + return P { left*((1-left-right)+V(1))^0*right } end local nany=utf8char/"" -function lpeg.counter(pattern)
- pattern=Cs((P(pattern)/" "+nany)^0)
- return function(str)
- return #lpegmatch(pattern,str)
- end
+function lpeg.counter(pattern) + pattern=Cs((P(pattern)/" "+nany)^0) + return function(str) + return #lpegmatch(pattern,str) + end end utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters
-local utfgmatch=utf and utf.gmatch
+local utfcharacters=utf and utf.characters or string.utfcharacters +local utfgmatch=utf and utf.gmatch local utfchar=utf and utf.char lpeg.UP=lpeg.P if utfcharacters then - function lpeg.US(str)
- local p=P(false)
- for uc in utfcharacters(str) do
- p=p+P(uc)
- end
- return p
+ function lpeg.US(str) + local p=P(false) + for uc in utfcharacters(str) do + p=p+P(uc) + end + return p end elseif utfgmatch then - function lpeg.US(str)
- local p=P(false)
- for uc in utfgmatch(str,".") do
- p=p+P(uc)
- end
- return p
+ function lpeg.US(str) + local p=P(false) + for uc in utfgmatch(str,".") do + p=p+P(uc) + end + return p end else - function lpeg.US(str)
- local p=P(false)
- local f=function(uc)
- p=p+P(uc)
- end
- lpegmatch((utf8char/f)^0,str)
- return p
+ function lpeg.US(str) + local p=P(false) + local f=function(uc) + p=p+P(uc) + end + lpegmatch((utf8char/f)^0,str) + return p end end local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more)
- local first,last
- if type(str)=="number" then
- first=str
- last=more or first
- else
- first,last=lpegmatch(range,str)
- if not last then
- return P(str)
- end
- end
- if first==last then
- return P(str)
+function lpeg.UR(str,more) + local first,last + if type(str)=="number" then + first=str + last=more or first + else + first,last=lpegmatch(range,str) + if not last then + return P(str) + end + end + if first==last then + return P(str) elseif utfchar and (last-first<8) then - local p=P(false)
- for i=first,last do
- p=p+P(utfchar(i))
- end
+ local p=P(false) + for i=first,last do + p=p+P(utfchar(i)) + end return p - else
- local f=function(b)
- return b>=first and b<=last
+ else + local f=function(b) + return b>=first and b<=last end return utf8byte/f - end
+ end end -function lpeg.is_lpeg(p)
- return p and lpegtype(p)=="pattern"
+function lpeg.is_lpeg(p) + return p and lpegtype(p)=="pattern" end function lpeg.oneof(list,...) - if type(list)~="table" then
- list={ list,... }
+ if type(list)~="table" then + list={ list,... } + end + local p=P(list[1]) + for l=2,#list do + p=p+P(list[l]) end - local p=P(list[1])
- for l=2,#list do
- p=p+P(list[l])
- end
- return p
+ return p end local sort=table.sort -local function copyindexed(old)
- local new={}
- for i=1,#old do
- new[i]=old
- end
- return new
-end -local function sortedkeys(tab)
- local keys,s={},0
- for key,_ in next,tab do
- s=s+1
- keys[s]=key
- end
- sort(keys)
- return keys
-end -function lpeg.append(list,pp,delayed,checked)
- local p=pp
- if #list>0 then
- local keys=copyindexed(list)
- sort(keys)
- for i=#keys,1,-1 do
- local k=keys[i]
- if p then
- p=P(k)+p
- else
- p=P(k)
- end
- end
+local function copyindexed(old) + local new={} + for i=1,#old do + new[i]=old + end + return new +end +local function sortedkeys(tab) + local keys,s={},0 + for key,_ in next,tab do + s=s+1 + keys[s]=key + end + sort(keys) + return keys +end +function lpeg.append(list,pp,delayed,checked) + local p=pp + if #list>0 then + local keys=copyindexed(list) + sort(keys) + for i=#keys,1,-1 do + local k=keys[i] + if p then + p=P(k)+p + else + p=P(k) + end + end elseif delayed then - local keys=sortedkeys(list)
- if p then
- for i=1,#keys,1 do
- local k=keys[i]
- local v=list[k]
- p=P(k)/list+p
- end
- else
- for i=1,#keys do
- local k=keys[i]
- local v=list[k]
- if p then
- p=P(k)+p
- else
- p=P(k)
- end
- end
- if p then
- p=p/list
- end
- end
+ local keys=sortedkeys(list) + if p then + for i=1,#keys,1 do + local k=keys[i] + local v=list[k] + p=P(k)/list+p + end + else + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)+p + else + p=P(k) + end + end + if p then + p=p/list + end + end elseif checked then - local keys=sortedkeys(list)
- for i=1,#keys do
- local k=keys[i]
- local v=list[k]
- if p then
- if k==v then
- p=P(k)+p
- else
- p=P(k)/v+p
- end
- else
- if k==v then
- p=P(k)
- else
- p=P(k)/v
- end
- end
- end
- else
- local keys=sortedkeys(list)
- for i=1,#keys do
- local k=keys[i]
- local v=list[k]
- if p then
- p=P(k)/v+p
- else
- p=P(k)/v
- end
- end
- end
- return p
-end -local function make(t)
- local p
- local keys=sortedkeys(t)
- for i=1,#keys do
- local k=keys[i]
- local v=t[k]
- if not p then
- if next(v) then
- p=P(k)*make(v)
- else
- p=P(k)
- end
- else
- if next(v) then
- p=p+P(k)*make(v)
- else
- p=p+P(k)
- end
- end
- end
- return p
+ local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + if k==v then + p=P(k)+p + else + p=P(k)/v+p + end + else + if k==v then + p=P(k) + else + p=P(k)/v + end + end + end + else + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)/v+p + else + p=P(k)/v + end + end + end + return p +end +local function make(t) + local p + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + local v=t[k] + if not p then + if next(v) then + p=P(k)*make(v) + else + p=P(k) + end + else + if next(v) then + p=p+P(k)*make(v) + else + p=p+P(k) + end + end + end + return p end function lpeg.utfchartabletopattern(list) - local tree={}
- for i=1,#list do
- local t=tree
- for c in gmatch(list[i],".") do
- if not t[c] then
- t[c]={}
- end
- t=t[c]
- end
- end
- return make(tree)
+ local tree={} + for i=1,#list do + local t=tree + for c in gmatch(list[i],".") do + if not t[c] then + t[c]={} + end + t=t[c] + end + end + return make(tree) end patterns.containseol=lpeg.finder(eol) -local function nextstep(n,step,result)
+local function nextstep(n,step,result) local m=n%step local d=floor(n/step) - if d>0 then
- local v=V(tostring(step))
- local s=result.start
- for i=1,d do
- if s then
- s=v*s
- else
- s=v
- end
- end
- result.start=s
- end
- if step>1 and result.start then
- local v=V(tostring(step/2))
- result[tostring(step)]=v*v
- end
- if step>0 then
- return nextstep(m,step/2,result)
- else
- return result
- end
-end -function lpeg.times(pattern,n)
- return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
-end -local digit=R("09")
-local period=P(".")
-local zero=P("0")
+ if d>0 then + local v=V(tostring(step)) + local s=result.start + for i=1,d do + if s then + s=v*s + else + s=v + end + end + result.start=s + end + if step>1 and result.start then + local v=V(tostring(step/2)) + result[tostring(step)]=v*v + end + if step>0 then + return nextstep(m,step/2,result) + else + return result + end +end +function lpeg.times(pattern,n) + return P(nextstep(n,2^16,{ "start",["1"]=pattern })) +end +local digit=R("09") +local period=P(".") +local zero=P("0") local trailingzeros=zero^0*-digit -local case_1=period*trailingzeros/""
-local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"")
-local number=digit^1*(case_1+case_2)
+local case_1=period*trailingzeros/"" +local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") +local number=digit^1*(case_1+case_2) local stripper=Cs((number+1)^0) lpeg.patterns.stripzeros=stripper @@ -661,1281 +661,1281 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-functions']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-functions']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } functions=functions or {} -function functions.dummy() end
+function functions.dummy() end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-string']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-string']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local string=string
-local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local string=string +local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower +local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote -function string.unquoted(str)
- return lpegmatch(unquoted,str) or str
+function string.unquoted(str) + return lpegmatch(unquoted,str) or str end -function string.quoted(str)
+function string.quoted(str) return format("%q",str) end function string.count(str,pattern) - local n=0
+ local n=0 for _ in gmatch(str,pattern) do - n=n+1
- end
- return n
+ n=n+1 + end + return n end function string.limit(str,n,sentinel) - if #str>n then
- sentinel=sentinel or "..."
- return sub(str,1,(n-#sentinel))..sentinel
- else
- return str
- end
-end -local stripper=patterns.stripper
-local collapser=patterns.collapser
+ if #str>n then + sentinel=sentinel or "..." + return sub(str,1,(n-#sentinel))..sentinel + else + return str + end +end +local stripper=patterns.stripper +local collapser=patterns.collapser local longtostring=patterns.longtostring -function string.strip(str)
- return lpegmatch(stripper,str) or ""
+function string.strip(str) + return lpegmatch(stripper,str) or "" end -function string.collapsespaces(str)
- return lpegmatch(collapser,str) or ""
+function string.collapsespaces(str) + return lpegmatch(collapser,str) or "" end -function string.longtostring(str)
- return lpegmatch(longtostring,str) or ""
+function string.longtostring(str) + return lpegmatch(longtostring,str) or "" end local pattern=P(" ")^0*P(-1) -function string.is_empty(str)
- if str=="" then
- return true
- else
- return lpegmatch(pattern,str) and true or false
- end
-end -local anything=patterns.anything
+function string.is_empty(str) + if str=="" then + return true + else + return lpegmatch(pattern,str) and true or false + end +end +local anything=patterns.anything local allescapes=Cc("%")*S(".-+%?()[]*") local someescapes=Cc("%")*S(".-+%()[]") local matchescapes=Cc(".")*S("*?") -local pattern_a=Cs ((allescapes+anything )^0 )
-local pattern_b=Cs ((someescapes+matchescapes+anything )^0 )
+local pattern_a=Cs ((allescapes+anything )^0 ) +local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) -function string.escapedpattern(str,simple)
- return lpegmatch(simple and pattern_b or pattern_a,str)
-end -function string.topattern(str,lowercase,strict)
- if str=="" or type(str)~="string" then
- return ".*"
- elseif strict then
- str=lpegmatch(pattern_c,str)
- else
- str=lpegmatch(pattern_b,str)
- end
- if lowercase then
- return lower(str)
- else
- return str
- end
-end -function string.valid(str,default)
- return (type(str)=="string" and str~="" and str) or default or nil
+function string.escapedpattern(str,simple) + return lpegmatch(simple and pattern_b or pattern_a,str) +end +function string.topattern(str,lowercase,strict) + if str=="" or type(str)~="string" then + return ".*" + elseif strict then + str=lpegmatch(pattern_c,str) + else + str=lpegmatch(pattern_b,str) + end + if lowercase then + return lower(str) + else + return str + end +end +function string.valid(str,default) + return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end local pattern=Ct(C(1)^0) -function string.totable(str)
- return lpegmatch(pattern,str)
+function string.totable(str) + return lpegmatch(pattern,str) end local replacer=lpeg.replacer("@","%%") -function string.tformat(fmt,...)
- return format(lpegmatch(replacer,fmt),...)
+function string.tformat(fmt,...) + return format(lpegmatch(replacer,fmt),...) end -string.quote=string.quoted
-string.unquote=string.unquoted
+string.quote=string.quoted +string.unquote=string.unquoted end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-table']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-table']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local type,next,tostring,tonumber,ipairs,select=type,next,tostring,tonumber,ipairs,select
-local table,string=table,string
-local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove
-local format,lower,dump=string.format,string.lower,string.dump
-local getmetatable,setmetatable=getmetatable,setmetatable
-local getinfo=debug.getinfo
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local type,next,tostring,tonumber,ipairs,select=type,next,tostring,tonumber,ipairs,select +local table,string=table,string +local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local format,lower,dump=string.format,string.lower,string.dump +local getmetatable,setmetatable=getmetatable,setmetatable +local getinfo=debug.getinfo +local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper -function table.strip(tab)
- local lst,l={},0
- for i=1,#tab do
- local s=lpegmatch(stripper,tab[i]) or ""
+function table.strip(tab) + local lst,l={},0 + for i=1,#tab do + local s=lpegmatch(stripper,tab[i]) or "" if s=="" then - else
- l=l+1
- lst[l]=s
- end
- end
- return lst
-end -function table.keys(t)
- if t then
- local keys,k={},0
- for key,_ in next,t do
- k=k+1
- keys[k]=key
- end
- return keys
- else
- return {}
- end
-end -local function compare(a,b)
+ else + l=l+1 + lst[l]=s + end + end + return lst +end +function table.keys(t) + if t then + local keys,k={},0 + for key,_ in next,t do + k=k+1 + keys[k]=key + end + return keys + else + return {} + end +end +local function compare(a,b) local ta,tb=type(a),type(b) - if ta==tb then
- return a<b
- else
- return tostring(a)<tostring(b)
- end
-end -local function sortedkeys(tab)
- if tab then
+ if ta==tb then + return a<b + else + return tostring(a)<tostring(b) + end +end +local function sortedkeys(tab) + if tab then local srt,category,s={},0,0 - for key,_ in next,tab do
- s=s+1
- srt[s]=key
+ for key,_ in next,tab do + s=s+1 + srt[s]=key if category==3 then - else
- local tkey=type(key)
- if tkey=="string" then
- category=(category==2 and 3) or 1
- elseif tkey=="number" then
- category=(category==1 and 3) or 2
- else
- category=3
- end
- end
- end
- if category==0 or category==3 then
- sort(srt,compare)
- else
- sort(srt)
- end
- return srt
- else
- return {}
- end
+ else + local tkey=type(key) + if tkey=="string" then + category=(category==2 and 3) or 1 + elseif tkey=="number" then + category=(category==1 and 3) or 2 + else + category=3 + end + end + end + if category==0 or category==3 then + sort(srt,compare) + else + sort(srt) + end + return srt + else + return {} + end end local function sortedhashkeys(tab,cmp) - if tab then
- local srt,s={},0
- for key,_ in next,tab do
- if key then
- s=s+1
- srt[s]=key
- end
- end
- sort(srt,cmp)
- return srt
- else
- return {}
- end
-end -function table.allkeys(t)
- local keys={}
- for k,v in next,t do
- for k,v in next,v do
- keys[k]=true
- end
- end
- return sortedkeys(keys)
-end -table.sortedkeys=sortedkeys
+ if tab then + local srt,s={},0 + for key,_ in next,tab do + if key then + s=s+1 + srt[s]=key + end + end + sort(srt,cmp) + return srt + else + return {} + end +end +function table.allkeys(t) + local keys={} + for k,v in next,t do + for k,v in next,v do + keys[k]=true + end + end + return sortedkeys(keys) +end +table.sortedkeys=sortedkeys table.sortedhashkeys=sortedhashkeys local function nothing() end -local function sortedhash(t,cmp)
- if t then
- local s
+local function sortedhash(t,cmp) + if t then + local s if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
- else
+ s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else s=sortedkeys(t) - end
- local n=0
- local function kv(s)
- n=n+1
- local k=s[n]
- return k,t[k]
- end
- return kv,s
- else
- return nothing
- end
-end -table.sortedhash=sortedhash
+ end + local n=0 + local function kv(s) + n=n+1 + local k=s[n] + return k,t[k] + end + return kv,s + else + return nothing + end +end +table.sortedhash=sortedhash table.sortedpairs=sortedhash -function table.append(t,list)
- local n=#t
- for i=1,#list do
- n=n+1
- t[n]=list[i]
- end
- return t
-end -function table.prepend(t,list)
- local nl=#list
- local nt=nl+#t
- for i=#t,1,-1 do
- t[nt]=t[i]
- nt=nt-1
- end
- for i=1,#list do
- t[i]=list[i]
- end
- return t
+function table.append(t,list) + local n=#t + for i=1,#list do + n=n+1 + t[n]=list[i] + end + return t +end +function table.prepend(t,list) + local nl=#list + local nt=nl+#t + for i=#t,1,-1 do + t[nt]=t[i] + nt=nt-1 + end + for i=1,#list do + t[i]=list[i] + end + return t end function table.merge(t,...) - t=t or {}
- for i=1,select("#",...) do
- for k,v in next,(select(i,...)) do
- t[k]=v
- end
- end
- return t
-end -function table.merged(...)
- local t={}
- for i=1,select("#",...) do
- for k,v in next,(select(i,...)) do
- t[k]=v
- end
- end
- return t
-end -function table.imerge(t,...)
- local nt=#t
- for i=1,select("#",...) do
- local nst=select(i,...)
- for j=1,#nst do
- nt=nt+1
- t[nt]=nst[j]
- end
- end
- return t
-end -function table.imerged(...)
- local tmp,ntmp={},0
- for i=1,select("#",...) do
- local nst=select(i,...)
- for j=1,#nst do
- ntmp=ntmp+1
- tmp[ntmp]=nst[j]
- end
- end
- return tmp
+ t=t or {} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v + end + end + return t +end +function table.merged(...) + local t={} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v + end + end + return t +end +function table.imerge(t,...) + local nt=#t + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + nt=nt+1 + t[nt]=nst[j] + end + end + return t +end +function table.imerged(...) + local tmp,ntmp={},0 + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + ntmp=ntmp+1 + tmp[ntmp]=nst[j] + end + end + return tmp end local function fastcopy(old,metatabletoo) - if old then
- local new={}
- for k,v in next,old do
- if type(v)=="table" then
+ if old then + local new={} + for k,v in next,old do + if type(v)=="table" then new[k]=fastcopy(v,metatabletoo) - else
- new[k]=v
- end
- end
+ else + new[k]=v + end + end if metatabletoo then - local mt=getmetatable(old)
- if mt then
- setmetatable(new,mt)
- end
- end
- return new
- else
- return {}
- end
+ local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end + end + return new + else + return {} + end end local function copy(t,tables) - tables=tables or {}
- local tcopy={}
- if not tables[t] then
- tables[t]=tcopy
- end
+ tables=tables or {} + local tcopy={} + if not tables[t] then + tables[t]=tcopy + end for i,v in next,t do - if type(i)=="table" then
- if tables[i] then
- i=tables[i]
- else
- i=copy(i,tables)
- end
- end
- if type(v)~="table" then
- tcopy[i]=v
- elseif tables[v] then
- tcopy[i]=tables[v]
- else
- tcopy[i]=copy(v,tables)
- end
- end
- local mt=getmetatable(t)
- if mt then
- setmetatable(tcopy,mt)
- end
- return tcopy
-end -table.fastcopy=fastcopy
+ if type(i)=="table" then + if tables[i] then + i=tables[i] + else + i=copy(i,tables) + end + end + if type(v)~="table" then + tcopy[i]=v + elseif tables[v] then + tcopy[i]=tables[v] + else + tcopy[i]=copy(v,tables) + end + end + local mt=getmetatable(t) + if mt then + setmetatable(tcopy,mt) + end + return tcopy +end +table.fastcopy=fastcopy table.copy=copy function table.derive(parent) - local child={}
- if parent then
- setmetatable(child,{ __index=parent })
- end
- return child
-end -function table.tohash(t,value)
- local h={}
- if t then
- if value==nil then value=true end
+ local child={} + if parent then + setmetatable(child,{ __index=parent }) + end + return child +end +function table.tohash(t,value) + local h={} + if t then + if value==nil then value=true end for _,v in next,t do - h[v]=value
- end
- end
- return h
+ h[v]=value + end + end + return h end -function table.fromhash(t)
- local hsh,h={},0
+function table.fromhash(t) + local hsh,h={},0 for k,v in next,t do - if v then
- h=h+1
- hsh[h]=k
- end
- end
- return hsh
+ if v then + h=h+1 + hsh[h]=k + end + end + return hsh end local noquotes,hexify,handle,reduce,compact,inline,functions local reserved=table.tohash { - 'and','break','do','else','elseif','end','false','for','function','if',
- 'in','local','nil','not','or','repeat','return','then','true','until','while',
+ 'and','break','do','else','elseif','end','false','for','function','if', + 'in','local','nil','not','or','repeat','return','then','true','until','while', } -local function simple_table(t)
- if #t>0 then
- local n=0
- for _,v in next,t do
- n=n+1
- end
- if n==#t then
- local tt,nt={},0
- for i=1,#t do
- local v=t[i]
- local tv=type(v)
- if tv=="number" then
- nt=nt+1
- if hexify then
- tt[nt]=format("0x%04X",v)
- else
+local function simple_table(t) + if #t>0 then + local n=0 + for _,v in next,t do + n=n+1 + end + if n==#t then + local tt,nt={},0 + for i=1,#t do + local v=t[i] + local tv=type(v) + if tv=="number" then + nt=nt+1 + if hexify then + tt[nt]=format("0x%04X",v) + else tt[nt]=tostring(v) - end
- elseif tv=="boolean" then
- nt=nt+1
- tt[nt]=tostring(v)
- elseif tv=="string" then
- nt=nt+1
- tt[nt]=format("%q",v)
- else
- tt=nil
- break
- end
- end
- return tt
- end
- end
- return nil
+ end + elseif tv=="boolean" then + nt=nt+1 + tt[nt]=tostring(v) + elseif tv=="string" then + nt=nt+1 + tt[nt]=format("%q",v) + else + tt=nil + break + end + end + return tt + end + end + return nil end local propername=patterns.propername local function dummy() end -local function do_serialize(root,name,depth,level,indexed)
- if level>0 then
- depth=depth.." "
- if indexed then
- handle(format("%s{",depth))
- else
- local tn=type(name)
- if tn=="number" then
- if hexify then
- handle(format("%s[0x%04X]={",depth,name))
- else
- handle(format("%s[%s]={",depth,name))
- end
- elseif tn=="string" then
- if noquotes and not reserved[name] and lpegmatch(propername,name) then
- handle(format("%s%s={",depth,name))
- else
- handle(format("%s[%q]={",depth,name))
- end
- elseif tn=="boolean" then
- handle(format("%s[%s]={",depth,tostring(name)))
- else
- handle(format("%s{",depth))
- end
- end
+local function do_serialize(root,name,depth,level,indexed) + if level>0 then + depth=depth.." " + if indexed then + handle(format("%s{",depth)) + else + local tn=type(name) + if tn=="number" then + if hexify then + handle(format("%s[0x%04X]={",depth,name)) + else + handle(format("%s[%s]={",depth,name)) + end + elseif tn=="string" then + if noquotes and not reserved[name] and lpegmatch(propername,name) then + handle(format("%s%s={",depth,name)) + else + handle(format("%s[%q]={",depth,name)) + end + elseif tn=="boolean" then + handle(format("%s[%s]={",depth,tostring(name))) + else + handle(format("%s{",depth)) + end + end end if root and next(root) then - local first,last=nil,0
- if compact then
- last=#root
- for k=1,last do
- if root[k]==nil then
- last=k-1
- break
- end
- end
- if last>0 then
- first=1
- end
- end
- local sk=sortedkeys(root)
- for i=1,#sk do
- local k=sk[i]
+ local first,last=nil,0 + if compact then + last=#root + for k=1,last do + if root[k]==nil then + last=k-1 + break + end + end + if last>0 then + first=1 + end + end + local sk=sortedkeys(root) + for i=1,#sk do + local k=sk[i] local v=root[k] - local t,tk=type(v),type(k)
- if compact and first and tk=="number" and k>=first and k<=last then
- if t=="number" then
- if hexify then
- handle(format("%s 0x%04X,",depth,v))
- else
+ local t,tk=type(v),type(k) + if compact and first and tk=="number" and k>=first and k<=last then + if t=="number" then + if hexify then + handle(format("%s 0x%04X,",depth,v)) + else handle(format("%s %s,",depth,v)) - end
- elseif t=="string" then
- if reduce and tonumber(v) then
- handle(format("%s %s,",depth,v))
- else
- handle(format("%s %q,",depth,v))
- end
- elseif t=="table" then
- if not next(v) then
- handle(format("%s {},",depth))
+ end + elseif t=="string" then + if reduce and tonumber(v) then + handle(format("%s %s,",depth,v)) + else + handle(format("%s %q,",depth,v)) + end + elseif t=="table" then + if not next(v) then + handle(format("%s {},",depth)) elseif inline then - local st=simple_table(v)
- if st then
- handle(format("%s { %s },",depth,concat(st,", ")))
- else
- do_serialize(v,k,depth,level+1,true)
- end
- else
- do_serialize(v,k,depth,level+1,true)
- end
- elseif t=="boolean" then
- handle(format("%s %s,",depth,tostring(v)))
- elseif t=="function" then
- if functions then
- handle(format('%s load(%q),',depth,dump(v)))
- else
- handle(format('%s "function",',depth))
- end
- else
- handle(format("%s %q,",depth,tostring(v)))
- end
+ local st=simple_table(v) + if st then + handle(format("%s { %s },",depth,concat(st,", "))) + else + do_serialize(v,k,depth,level+1,true) + end + else + do_serialize(v,k,depth,level+1,true) + end + elseif t=="boolean" then + handle(format("%s %s,",depth,tostring(v))) + elseif t=="function" then + if functions then + handle(format('%s load(%q),',depth,dump(v))) + else + handle(format('%s "function",',depth)) + end + else + handle(format("%s %q,",depth,tostring(v))) + end elseif k=="__p__" then - if false then
- handle(format("%s __p__=nil,",depth))
- end
- elseif t=="number" then
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
- else
+ if false then + handle(format("%s __p__=nil,",depth)) + end + elseif t=="number" then + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) + else handle(format("%s [%s]=%s,",depth,k,v)) - end
- elseif tk=="boolean" then
- if hexify then
- handle(format("%s [%s]=0x%04X,",depth,tostring(k),v))
- else
+ end + elseif tk=="boolean" then + if hexify then + handle(format("%s [%s]=0x%04X,",depth,tostring(k),v)) + else handle(format("%s [%s]=%s,",depth,tostring(k),v)) - end
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- if hexify then
- handle(format("%s %s=0x%04X,",depth,k,v))
- else
+ end + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + if hexify then + handle(format("%s %s=0x%04X,",depth,k,v)) + else handle(format("%s %s=%s,",depth,k,v)) - end
- else
- if hexify then
- handle(format("%s [%q]=0x%04X,",depth,k,v))
- else
+ end + else + if hexify then + handle(format("%s [%q]=0x%04X,",depth,k,v)) + else handle(format("%s [%q]=%s,",depth,k,v)) - end
- end
- elseif t=="string" then
- if reduce and tonumber(v) then
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=%s,",depth,k,v))
- else
- handle(format("%s [%s]=%s,",depth,k,v))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]=%s,",depth,tostring(k),v))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s=%s,",depth,k,v))
- else
- handle(format("%s [%q]=%s,",depth,k,v))
- end
- else
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=%q,",depth,k,v))
- else
- handle(format("%s [%s]=%q,",depth,k,v))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]=%q,",depth,tostring(k),v))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s=%q,",depth,k,v))
- else
- handle(format("%s [%q]=%q,",depth,k,v))
- end
- end
- elseif t=="table" then
- if not next(v) then
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]={},",depth,k))
- else
- handle(format("%s [%s]={},",depth,k))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]={},",depth,tostring(k)))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s={},",depth,k))
- else
- handle(format("%s [%q]={},",depth,k))
- end
- elseif inline then
- local st=simple_table(v)
- if st then
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
- else
- handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]={ %s },",depth,tostring(k),concat(st,", ")))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
- else
- handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
- end
- else
- do_serialize(v,k,depth,level+1)
- end
- else
- do_serialize(v,k,depth,level+1)
- end
- elseif t=="boolean" then
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
- else
- handle(format("%s [%s]=%s,",depth,k,tostring(v)))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]=%s,",depth,tostring(k),tostring(v)))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s=%s,",depth,k,tostring(v)))
- else
- handle(format("%s [%q]=%s,",depth,k,tostring(v)))
- end
- elseif t=="function" then
- if functions then
+ end + end + elseif t=="string" then + if reduce and tonumber(v) then + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=%s,",depth,k,v)) + else + handle(format("%s [%s]=%s,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%s,",depth,tostring(k),v)) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end + else + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=%q,",depth,k,v)) + else + handle(format("%s [%s]=%q,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,tostring(k),v)) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) + else + handle(format("%s [%q]=%q,",depth,k,v)) + end + end + elseif t=="table" then + if not next(v) then + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]={},",depth,k)) + else + handle(format("%s [%s]={},",depth,k)) + end + elseif tk=="boolean" then + handle(format("%s [%s]={},",depth,tostring(k))) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={},",depth,k)) + else + handle(format("%s [%q]={},",depth,k)) + end + elseif inline then + local st=simple_table(v) + if st then + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) + end + elseif tk=="boolean" then + handle(format("%s [%s]={ %s },",depth,tostring(k),concat(st,", "))) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) + end + else + do_serialize(v,k,depth,level+1) + end + else + do_serialize(v,k,depth,level+1) + end + elseif t=="boolean" then + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=%s,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%s,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%s,",depth,tostring(k),tostring(v))) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%s,",depth,k,tostring(v))) + end + elseif t=="function" then + if functions then local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=load(%q),",depth,k,f))
- else
- handle(format("%s [%s]=load(%q),",depth,k,f))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]=load(%q),",depth,tostring(k),f))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s=load(%q),",depth,k,f))
- else
- handle(format("%s [%q]=load(%q),",depth,k,f))
- end
- end
- else
- if tk=="number" then
- if hexify then
- handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
- else
- handle(format("%s [%s]=%q,",depth,k,tostring(v)))
- end
- elseif tk=="boolean" then
- handle(format("%s [%s]=%q,",depth,tostring(k),tostring(v)))
- elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
- handle(format("%s %s=%q,",depth,k,tostring(v)))
- else
- handle(format("%s [%q]=%q,",depth,k,tostring(v)))
- end
- end - end
- end
- if level>0 then
- handle(format("%s},",depth))
- end
+ if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=load(%q),",depth,tostring(k),f)) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=load(%q),",depth,k,f)) + else + handle(format("%s [%q]=load(%q),",depth,k,f)) + end + end + else + if tk=="number" then + if hexify then + handle(format("%s [0x%04X]=%q,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%q,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,tostring(k),tostring(v))) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%q,",depth,k,tostring(v))) + end + end + end + end + if level>0 then + handle(format("%s},",depth)) + end end local function serialize(_handle,root,name,specification) - local tname=type(name)
- if type(specification)=="table" then
- noquotes=specification.noquotes
- hexify=specification.hexify
- handle=_handle or specification.handle or print
- reduce=specification.reduce or false
- functions=specification.functions
- compact=specification.compact
- inline=specification.inline and compact
- if functions==nil then
- functions=true
- end
- if compact==nil then
- compact=true
- end
- if inline==nil then
- inline=compact
- end
- else
- noquotes=false
- hexify=false
- handle=_handle or print
- reduce=false
- compact=true
- inline=true
- functions=true
- end
- if tname=="string" then
- if name=="return" then
- handle("return {")
- else
- handle(name.."={")
- end
- elseif tname=="number" then
- if hexify then
- handle(format("[0x%04X]={",name))
- else
- handle("["..name.."]={")
- end
- elseif tname=="boolean" then
- if name then
- handle("return {")
- else
- handle("{")
- end
- else
- handle("t={")
- end
+ local tname=type(name) + if type(specification)=="table" then + noquotes=specification.noquotes + hexify=specification.hexify + handle=_handle or specification.handle or print + reduce=specification.reduce or false + functions=specification.functions + compact=specification.compact + inline=specification.inline and compact + if functions==nil then + functions=true + end + if compact==nil then + compact=true + end + if inline==nil then + inline=compact + end + else + noquotes=false + hexify=false + handle=_handle or print + reduce=false + compact=true + inline=true + functions=true + end + if tname=="string" then + if name=="return" then + handle("return {") + else + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%04X]={",name)) + else + handle("["..name.."]={") + end + elseif tname=="boolean" then + if name then + handle("return {") + else + handle("{") + end + else + handle("t={") + end if root then if getmetatable(root) then - local dummy=root._w_h_a_t_e_v_e_r_
- root._w_h_a_t_e_v_e_r_=nil
- end - if next(root) then
- do_serialize(root,name,"",0)
- end
- end
- handle("}")
-end -function table.serialize(root,name,specification)
- local t,n={},0
- local function flush(s)
- n=n+1
- t[n]=s
- end
- serialize(flush,root,name,specification)
- return concat(t,"\n")
+ local dummy=root._w_h_a_t_e_v_e_r_ + root._w_h_a_t_e_v_e_r_=nil + end + if next(root) then + do_serialize(root,name,"",0) + end + end + handle("}") +end +function table.serialize(root,name,specification) + local t,n={},0 + local function flush(s) + n=n+1 + t[n]=s + end + serialize(flush,root,name,specification) + return concat(t,"\n") end table.tohandle=serialize local maxtab=2*1024 -function table.tofile(filename,root,name,specification)
- local f=io.open(filename,'w')
- if f then
- if maxtab>1 then
- local t,n={},0
- local function flush(s)
- n=n+1
- t[n]=s
- if n>maxtab then
+function table.tofile(filename,root,name,specification) + local f=io.open(filename,'w') + if f then + if maxtab>1 then + local t,n={},0 + local function flush(s) + n=n+1 + t[n]=s + if n>maxtab then f:write(concat(t,"\n"),"\n") t,n={},0 - end
- end
- serialize(flush,root,name,specification)
- f:write(concat(t,"\n"),"\n")
- else
- local function flush(s)
- f:write(s,"\n")
- end
- serialize(flush,root,name,specification)
- end
- f:close()
- io.flush()
- end
+ end + end + serialize(flush,root,name,specification) + f:write(concat(t,"\n"),"\n") + else + local function flush(s) + f:write(s,"\n") + end + serialize(flush,root,name,specification) + end + f:close() + io.flush() + end end local function flattened(t,f,depth) - if f==nil then
- f={}
- depth=0xFFFF
+ if f==nil then + f={} + depth=0xFFFF elseif tonumber(f) then - depth=f
- f={}
- elseif not depth then
- depth=0xFFFF
- end
- for k,v in next,t do
- if type(k)~="number" then
- if depth>0 and type(v)=="table" then
- flattened(v,f,depth-1)
- else
- f[#f+1]=v
- end
- end
- end
- for k=1,#t do
- local v=t[k]
- if depth>0 and type(v)=="table" then
- flattened(v,f,depth-1)
- else
- f[#f+1]=v
- end
- end
- return f
+ depth=f + f={} + elseif not depth then + depth=0xFFFF + end + for k,v in next,t do + if type(k)~="number" then + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end + end + end + for k=1,#t do + local v=t[k] + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end + end + return f end table.flattened=flattened local function unnest(t,f) if not f then f={} - end
- for i=1,#t do
- local v=t[i]
- if type(v)=="table" then
- if type(v[1])=="table" then
- unnest(v,f)
- else
- f[#f+1]=v
- end
- else
- f[#f+1]=v
- end
- end
- return f
+ end + for i=1,#t do + local v=t[i] + if type(v)=="table" then + if type(v[1])=="table" then + unnest(v,f) + else + f[#f+1]=v + end + else + f[#f+1]=v + end + end + return f end function table.unnest(t) - return unnest(t)
+ return unnest(t) end local function are_equal(a,b,n,m) - if a and b and #a==#b then
- n=n or 1
- m=m or #a
- for i=n,m do
- local ai,bi=a[i],b[i]
+ if a and b and #a==#b then + n=n or 1 + m=m or #a + for i=n,m do + local ai,bi=a[i],b[i] if ai==bi then - elseif type(ai)=="table" and type(bi)=="table" then
- if not are_equal(ai,bi) then
- return false
- end
- else
- return false
- end
- end
- return true
- else
- return false
- end
+ elseif type(ai)=="table" and type(bi)=="table" then + if not are_equal(ai,bi) then + return false + end + else + return false + end + end + return true + else + return false + end end local function identical(a,b) - for ka,va in next,a do
- local vb=b[ka]
+ for ka,va in next,a do + local vb=b[ka] if va==vb then - elseif type(va)=="table" and type(vb)=="table" then
- if not identical(va,vb) then
- return false
- end
- else
- return false
- end
- end
- return true
-end -table.identical=identical
+ elseif type(va)=="table" and type(vb)=="table" then + if not identical(va,vb) then + return false + end + else + return false + end + end + return true +end +table.identical=identical table.are_equal=are_equal function table.compact(t) - if t then
- for k,v in next,t do
+ if t then + for k,v in next,t do if not next(v) then - t[k]=nil
- end
- end
- end
-end -function table.contains(t,v)
- if t then
- for i=1,#t do
- if t[i]==v then
- return i
- end
- end
- end
- return false
-end -function table.count(t)
- local n=0
- for k,v in next,t do
- n=n+1
- end
- return n
+ t[k]=nil + end + end + end +end +function table.contains(t,v) + if t then + for i=1,#t do + if t[i]==v then + return i + end + end + end + return false +end +function table.count(t) + local n=0 + for k,v in next,t do + n=n+1 + end + return n end function table.swapped(t,s) - local n={}
- if s then
- for k,v in next,s do
- n[k]=v
- end
- end
- for k,v in next,t do
- n[v]=k
- end
- return n
+ local n={} + if s then + for k,v in next,s do + n[k]=v + end + end + for k,v in next,t do + n[v]=k + end + return n end function table.mirrored(t) - local n={}
- for k,v in next,t do
- n[v]=k
- n[k]=v
- end
- return n
-end -function table.reversed(t)
- if t then
- local tt,tn={},#t
- if tn>0 then
- local ttn=0
- for i=tn,1,-1 do
- ttn=ttn+1
- tt[ttn]=t[i]
- end
- end
- return tt
- end
-end -function table.reverse(t)
- if t then
- local n=#t
- for i=1,floor(n/2) do
- local j=n-i+1
- t[i],t[j]=t[j],t[i]
- end
- return t
- end
+ local n={} + for k,v in next,t do + n[v]=k + n[k]=v + end + return n +end +function table.reversed(t) + if t then + local tt,tn={},#t + if tn>0 then + local ttn=0 + for i=tn,1,-1 do + ttn=ttn+1 + tt[ttn]=t[i] + end + end + return tt + end +end +function table.reverse(t) + if t then + local n=#t + for i=1,floor(n/2) do + local j=n-i+1 + t[i],t[j]=t[j],t[i] + end + return t + end end function table.sequenced(t,sep,simple) - if not t then
- return ""
- end
- local n=#t
- local s={}
+ if not t then + return "" + end + local n=#t + local s={} if n>0 then - for i=1,n do
- s[i]=tostring(t[i])
- end
+ for i=1,n do + s[i]=tostring(t[i]) + end else - n=0
- for k,v in sortedhash(t) do
- if simple then
- if v==true then
- n=n+1
- s[n]=k
- elseif v and v~="" then
- n=n+1
- s[n]=k.."="..tostring(v)
- end
- else
- n=n+1
- s[n]=k.."="..tostring(v)
- end
- end
- end
- return concat(s,sep or " | ")
-end -function table.print(t,...)
- if type(t)~="table" then
- print(tostring(t))
- else
- serialize(print,t,...)
- end
+ n=0 + for k,v in sortedhash(t) do + if simple then + if v==true then + n=n+1 + s[n]=k + elseif v and v~="" then + n=n+1 + s[n]=k.."="..tostring(v) + end + else + n=n+1 + s[n]=k.."="..tostring(v) + end + end + end + return concat(s,sep or " | ") +end +function table.print(t,...) + if type(t)~="table" then + print(tostring(t)) + else + serialize(print,t,...) + end end setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) -function table.sub(t,i,j)
- return { unpack(t,i,j) }
+function table.sub(t,i,j) + return { unpack(t,i,j) } end -function table.is_empty(t)
- return not t or not next(t)
+function table.is_empty(t) + return not t or not next(t) end -function table.has_one_entry(t)
- return t and not next(t,next(t))
+function table.has_one_entry(t) + return t and not next(t,next(t)) end function table.loweredkeys(t) - local l={}
- for k,v in next,t do
- l[lower(k)]=v
- end
- return l
-end -function table.unique(old)
- local hash={}
- local new={}
- local n=0
- for i=1,#old do
- local oi=old[i]
- if not hash[oi] then
- n=n+1
- new[n]=oi
- hash[oi]=true
- end
- end
- return new
-end -function table.sorted(t,...)
- sort(t,...)
+ local l={} + for k,v in next,t do + l[lower(k)]=v + end + return l +end +function table.unique(old) + local hash={} + local new={} + local n=0 + for i=1,#old do + local oi=old[i] + if not hash[oi] then + n=n+1 + new[n]=oi + hash[oi]=true + end + end + return new +end +function table.sorted(t,...) + sort(t,...) return t -end
+end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-io']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-io']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local io=io
-local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
-local concat=table.concat
-local floor=math.floor
+local io=io +local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format +local concat=table.concat +local floor=math.floor local type=type -if string.find(os.getenv("PATH"),";") then
- io.fileseparator,io.pathseparator="\\",";"
-else
- io.fileseparator,io.pathseparator="/",":"
-end -local function readall(f)
- return f:read("*all")
-end -local function readall(f)
- local size=f:seek("end")
- if size==0 then
- return ""
- elseif size<1024*1024 then
- f:seek("set",0)
- return f:read('*all')
- else
- local done=f:seek("set",0)
- if size<1024*1024 then
- step=1024*1024
- elseif size>16*1024*1024 then
- step=16*1024*1024
- else
- step=floor(size/(1024*1024))*1024*1024/8
- end
- local data={}
- while true do
- local r=f:read(step)
- if not r then
- return concat(data)
- else
- data[#data+1]=r
- end
- end
- end
+if string.find(os.getenv("PATH"),";") then + io.fileseparator,io.pathseparator="\\",";" +else + io.fileseparator,io.pathseparator="/",":" +end +local function readall(f) + return f:read("*all") +end +local function readall(f) + local size=f:seek("end") + if size==0 then + return "" + elseif size<1024*1024 then + f:seek("set",0) + return f:read('*all') + else + local done=f:seek("set",0) + if size<1024*1024 then + step=1024*1024 + elseif size>16*1024*1024 then + step=16*1024*1024 + else + step=floor(size/(1024*1024))*1024*1024/8 + end + local data={} + while true do + local r=f:read(step) + if not r then + return concat(data) + else + data[#data+1]=r + end + end + end end io.readall=readall function io.loaddata(filename,textmode) - local f=io.open(filename,(textmode and 'r') or 'rb')
+ local f=io.open(filename,(textmode and 'r') or 'rb') if f then - local data=readall(f)
- f:close()
- if #data>0 then
- return data
- end
- end
-end -function io.savedata(filename,data,joiner)
- local f=io.open(filename,"wb")
- if f then
- if type(data)=="table" then
- f:write(concat(data,joiner or ""))
- elseif type(data)=="function" then
- data(f)
- else
- f:write(data or "")
- end
- f:close()
- io.flush()
- return true
- else
- return false
- end
+ local data=readall(f) + f:close() + if #data>0 then + return data + end + end +end +function io.savedata(filename,data,joiner) + local f=io.open(filename,"wb") + if f then + if type(data)=="table" then + f:write(concat(data,joiner or "")) + elseif type(data)=="function" then + data(f) + else + f:write(data or "") + end + f:close() + io.flush() + return true + else + return false + end end function io.loadlines(filename,n) - local f=io.open(filename,'r')
+ local f=io.open(filename,'r') if not f then - elseif n then
- local lines={}
- for i=1,n do
- local line=f:read("*lines")
- if line then
- lines[#lines+1]=line
- else
- break
- end
- end
- f:close()
- lines=concat(lines,"\n")
- if #lines>0 then
- return lines
- end
- else
- local line=f:read("*line") or ""
- f:close()
- if #line>0 then
- return line
- end
- end
-end -function io.loadchunk(filename,n)
- local f=io.open(filename,'rb')
- if f then
- local data=f:read(n or 1024)
- f:close()
- if #data>0 then
- return data
- end
- end
-end -function io.exists(filename)
- local f=io.open(filename)
- if f==nil then
- return false
- else
- f:close()
- return true
- end
-end -function io.size(filename)
- local f=io.open(filename)
- if f==nil then
- return 0
- else
- local s=f:seek("end")
- f:close()
- return s
- end
-end -function io.noflines(f)
- if type(f)=="string" then
- local f=io.open(filename)
- if f then
- local n=f and io.noflines(f) or 0
- f:close()
- return n
- else
- return 0
- end
- else
- local n=0
- for _ in f:lines() do
- n=n+1
- end
- f:seek('set',0)
- return n
- end
-end -local nextchar={
- [ 4]=function(f)
- return f:read(1,1,1,1)
- end,
- [ 2]=function(f)
- return f:read(1,1)
- end,
- [ 1]=function(f)
- return f:read(1)
- end,
- [-2]=function(f)
- local a,b=f:read(1,1)
- return b,a
- end,
- [-4]=function(f)
- local a,b,c,d=f:read(1,1,1,1)
- return d,c,b,a
- end
+ elseif n then + local lines={} + for i=1,n do + local line=f:read("*lines") + if line then + lines[#lines+1]=line + else + break + end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=f:read("*line") or "" + f:close() + if #line>0 then + return line + end + end +end +function io.loadchunk(filename,n) + local f=io.open(filename,'rb') + if f then + local data=f:read(n or 1024) + f:close() + if #data>0 then + return data + end + end +end +function io.exists(filename) + local f=io.open(filename) + if f==nil then + return false + else + f:close() + return true + end +end +function io.size(filename) + local f=io.open(filename) + if f==nil then + return 0 + else + local s=f:seek("end") + f:close() + return s + end +end +function io.noflines(f) + if type(f)=="string" then + local f=io.open(filename) + if f then + local n=f and io.noflines(f) or 0 + f:close() + return n + else + return 0 + end + else + local n=0 + for _ in f:lines() do + n=n+1 + end + f:seek('set',0) + return n + end +end +local nextchar={ + [ 4]=function(f) + return f:read(1,1,1,1) + end, + [ 2]=function(f) + return f:read(1,1) + end, + [ 1]=function(f) + return f:read(1) + end, + [-2]=function(f) + local a,b=f:read(1,1) + return b,a + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + return d,c,b,a + end } -function io.characters(f,n)
- if f then
- return nextchar[n or 1],f
- end
-end -local nextbyte={
- [4]=function(f)
- local a,b,c,d=f:read(1,1,1,1)
- if d then
- return byte(a),byte(b),byte(c),byte(d)
- end
- end,
- [3]=function(f)
- local a,b,c=f:read(1,1,1)
- if b then
- return byte(a),byte(b),byte(c)
- end
- end,
- [2]=function(f)
- local a,b=f:read(1,1)
- if b then
- return byte(a),byte(b)
- end
- end,
- [1]=function (f)
- local a=f:read(1)
- if a then
- return byte(a)
- end
- end,
- [-2]=function (f)
- local a,b=f:read(1,1)
- if b then
- return byte(b),byte(a)
- end
- end,
- [-3]=function(f)
- local a,b,c=f:read(1,1,1)
- if b then
- return byte(c),byte(b),byte(a)
- end
- end,
- [-4]=function(f)
- local a,b,c,d=f:read(1,1,1,1)
- if d then
- return byte(d),byte(c),byte(b),byte(a)
- end
- end
+function io.characters(f,n) + if f then + return nextchar[n or 1],f + end +end +local nextbyte={ + [4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(a),byte(b),byte(c),byte(d) + end + end, + [3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(a),byte(b),byte(c) + end + end, + [2]=function(f) + local a,b=f:read(1,1) + if b then + return byte(a),byte(b) + end + end, + [1]=function (f) + local a=f:read(1) + if a then + return byte(a) + end + end, + [-2]=function (f) + local a,b=f:read(1,1) + if b then + return byte(b),byte(a) + end + end, + [-3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(c),byte(b),byte(a) + end + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(d),byte(c),byte(b),byte(a) + end + end } -function io.bytes(f,n)
- if f then
- return nextbyte[n or 1],f
- else
- return nil,nil
- end
-end -function io.ask(question,default,options)
- while true do
- io.write(question)
- if options then
- io.write(format(" [%s]",concat(options,"|")))
- end
- if default then
- io.write(format(" [%s]",default))
- end
- io.write(format(" "))
- io.flush()
- local answer=io.read()
- answer=gsub(answer,"^%s*(.*)%s*$","%1")
- if answer=="" and default then
- return default
- elseif not options then
- return answer
- else
- for k=1,#options do
- if options[k]==answer then
- return answer
- end
- end
- local pattern="^"..answer
- for k=1,#options do
- local v=options[k]
- if find(v,pattern) then
- return v
- end
- end
- end
- end
-end -local function readnumber(f,n,m)
- if m then
- f:seek("set",n)
- n=m
- end
- if n==1 then
- return byte(f:read(1))
- elseif n==2 then
- local a,b=byte(f:read(2),1,2)
- return 256*a+b
- elseif n==3 then
- local a,b,c=byte(f:read(3),1,3)
- return 256*256*a+256*b+c
- elseif n==4 then
- local a,b,c,d=byte(f:read(4),1,4)
- return 256*256*256*a+256*256*b+256*c+d
- elseif n==8 then
- local a,b=readnumber(f,4),readnumber(f,4)
- return 256*a+b
- elseif n==12 then
- local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
- return 256*256*a+256*b+c
- elseif n==-2 then
- local b,a=byte(f:read(2),1,2)
- return 256*a+b
- elseif n==-3 then
- local c,b,a=byte(f:read(3),1,3)
- return 256*256*a+256*b+c
- elseif n==-4 then
- local d,c,b,a=byte(f:read(4),1,4)
- return 256*256*256*a+256*256*b+256*c+d
- elseif n==-8 then
- local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
- return 256*256*256*256*256*256*256*a+256*256*256*256*256*256*b+256*256*256*256*256*c+256*256*256*256*d+256*256*256*e+256*256*f+256*g+h
- else
- return 0
- end
+function io.bytes(f,n) + if f then + return nextbyte[n or 1],f + else + return nil,nil + end +end +function io.ask(question,default,options) + while true do + io.write(question) + if options then + io.write(format(" [%s]",concat(options,"|"))) + end + if default then + io.write(format(" [%s]",default)) + end + io.write(format(" ")) + io.flush() + local answer=io.read() + answer=gsub(answer,"^%s*(.*)%s*$","%1") + if answer=="" and default then + return default + elseif not options then + return answer + else + for k=1,#options do + if options[k]==answer then + return answer + end + end + local pattern="^"..answer + for k=1,#options do + local v=options[k] + if find(v,pattern) then + return v + end + end + end + end +end +local function readnumber(f,n,m) + if m then + f:seek("set",n) + n=m + end + if n==1 then + return byte(f:read(1)) + elseif n==2 then + local a,b=byte(f:read(2),1,2) + return 256*a+b + elseif n==3 then + local a,b,c=byte(f:read(3),1,3) + return 256*256*a+256*b+c + elseif n==4 then + local a,b,c,d=byte(f:read(4),1,4) + return 256*256*256*a+256*256*b+256*c+d + elseif n==8 then + local a,b=readnumber(f,4),readnumber(f,4) + return 256*a+b + elseif n==12 then + local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) + return 256*256*a+256*b+c + elseif n==-2 then + local b,a=byte(f:read(2),1,2) + return 256*a+b + elseif n==-3 then + local c,b,a=byte(f:read(3),1,3) + return 256*256*a+256*b+c + elseif n==-4 then + local d,c,b,a=byte(f:read(4),1,4) + return 256*256*256*a+256*256*b+256*c+d + elseif n==-8 then + local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) + return 256*256*256*256*256*256*256*a+256*256*256*256*256*256*b+256*256*256*256*256*c+256*256*256*256*d+256*256*256*e+256*256*f+256*g+h + else + return 0 + end end io.readnumber=readnumber -function io.readstring(f,n,m)
- if m then
- f:seek("set",n)
- n=m
- end
- local str=gsub(f:read(n),"\000","")
- return str
+function io.readstring(f,n,m) + if m then + f:seek("set",n) + n=m + end + local str=gsub(f:read(n),"\000","") + return str end if not io.i_limiter then function io.i_limiter() end end if not io.o_limiter then function io.o_limiter() end end @@ -1944,862 +1944,862 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-file']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-file']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -file=file or {}
+file=file or {} local file=file -if not lfs then
- lfs=optionalrequire("lfs")
+if not lfs then + lfs=optionalrequire("lfs") end if not lfs then - lfs={
- getcurrentdir=function()
- return "."
- end,
- attributes=function()
- return nil
- end,
- isfile=function(name)
- local f=io.open(name,'rb')
- if f then
- f:close()
- return true
- end
- end,
- isdir=function(name)
- print("you need to load lfs")
- return false
- end
+ lfs={ + getcurrentdir=function() + return "." + end, + attributes=function() + return nil + end, + isfile=function(name) + local f=io.open(name,'rb') + if f then + f:close() + return true + end + end, + isdir=function(name) + print("you need to load lfs") + return false + end } elseif not lfs.isfile then local attributes=lfs.attributes - function lfs.isdir(name)
- return attributes(name,"mode")=="directory"
+ function lfs.isdir(name) + return attributes(name,"mode")=="directory" end - function lfs.isfile(name)
- return attributes(name,"mode")=="file"
+ function lfs.isfile(name) + return attributes(name,"mode")=="file" end end -local insert,concat=table.insert,table.concat
-local match,find,gmatch=string.match,string.find,string.gmatch
-local lpegmatch=lpeg.match
-local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
+local insert,concat=table.insert,table.concat +local match,find,gmatch=string.match,string.find,string.gmatch +local lpegmatch=lpeg.match +local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local colon=P(":")
-local period=P(".")
-local periods=P("..")
-local fwslash=P("/")
-local bwslash=P("\\")
-local slashes=S("\\/")
-local noperiod=1-period
-local noslashes=1-slashes
-local name=noperiod^1
+local colon=P(":") +local period=P(".") +local periods=P("..") +local fwslash=P("/") +local bwslash=P("\\") +local slashes=S("\\/") +local noperiod=1-period +local noslashes=1-slashes +local name=noperiod^1 local suffix=period/""*(1-period-slashes)^1*-1 local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) -local function pathpart(name,default)
- return name and lpegmatch(pattern,name) or default or ""
+local function pathpart(name,default) + return name and lpegmatch(pattern,name) or default or "" end local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1 -local function basename(name)
- return name and lpegmatch(pattern,name) or name
+local function basename(name) + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0 -local function nameonly(name)
- return name and lpegmatch(pattern,name) or name
+local function nameonly(name) + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1 -local function suffixonly(name)
- return name and lpegmatch(pattern,name) or ""
+local function suffixonly(name) + return name and lpegmatch(pattern,name) or "" end -file.pathpart=pathpart
-file.basename=basename
-file.nameonly=nameonly
-file.suffixonly=suffixonly
+file.pathpart=pathpart +file.basename=basename +file.nameonly=nameonly +file.suffixonly=suffixonly file.suffix=suffixonly file.dirname=pathpart file.extname=suffixonly -local drive=C(R("az","AZ"))*colon
-local path=C((noslashes^0*slashes)^0)
-local suffix=period*C(P(1-period)^0*P(-1))
-local base=C((1-suffix)^0)
+local drive=C(R("az","AZ"))*colon +local path=C((noslashes^0*slashes)^0) +local suffix=period*C(P(1-period)^0*P(-1)) +local base=C((1-suffix)^0) local rest=C(P(1)^0) -drive=drive+Cc("")
-path=path+Cc("")
-base=base+Cc("")
+drive=drive+Cc("") +path=path+Cc("") +base=base+Cc("") suffix=suffix+Cc("") -local pattern_a=drive*path*base*suffix
-local pattern_b=path*base*suffix
+local pattern_a=drive*path*base*suffix +local pattern_b=path*base*suffix local pattern_c=C(drive*path)*C(base*suffix) local pattern_d=path*rest -function file.splitname(str,splitdrive)
+function file.splitname(str,splitdrive) if not str then - elseif splitdrive then
+ elseif splitdrive then return lpegmatch(pattern_a,str) - else
+ else return lpegmatch(pattern_b,str) - end
+ end end -function file.splitbase(str)
- if str then
+function file.splitbase(str) + if str then return lpegmatch(pattern_d,str) - else
+ else return "",str - end
+ end end -function file.nametotable(str,splitdrive)
- if str then
+function file.nametotable(str,splitdrive) + if str then local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) - if splitdrive then
- return {
- path=path,
- drive=drive,
- subpath=subpath,
- name=name,
- base=base,
- suffix=suffix,
- }
- else
- return {
- path=path,
- name=name,
- base=base,
- suffix=suffix,
- }
- end
- end
+ if splitdrive then + return { + path=path, + drive=drive, + subpath=subpath, + name=name, + base=base, + suffix=suffix, + } + else + return { + path=path, + name=name, + base=base, + suffix=suffix, + } + end + end end local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1) -function file.removesuffix(name)
- return name and lpegmatch(pattern,name)
+function file.removesuffix(name) + return name and lpegmatch(pattern,name) end -local suffix=period/""*(1-period-slashes)^1*-1
+local suffix=period/""*(1-period-slashes)^1*-1 local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix) -function file.addsuffix(filename,suffix,criterium)
- if not filename or not suffix or suffix=="" then
- return filename
- elseif criterium==true then
- return filename.."."..suffix
- elseif not criterium then
- local n,s=lpegmatch(pattern,filename)
- if not s or s=="" then
- return filename.."."..suffix
- else
- return filename
- end
- else
- local n,s=lpegmatch(pattern,filename)
- if s and s~="" then
- local t=type(criterium)
+function file.addsuffix(filename,suffix,criterium) + if not filename or not suffix or suffix=="" then + return filename + elseif criterium==true then + return filename.."."..suffix + elseif not criterium then + local n,s=lpegmatch(pattern,filename) + if not s or s=="" then + return filename.."."..suffix + else + return filename + end + else + local n,s=lpegmatch(pattern,filename) + if s and s~="" then + local t=type(criterium) if t=="table" then - for i=1,#criterium do
- if s==criterium[i] then
- return filename
- end
- end
+ for i=1,#criterium do + if s==criterium[i] then + return filename + end + end elseif t=="string" then - if s==criterium then
- return filename
- end
- end
- end
- return (n or filename).."."..suffix
- end
-end -local suffix=period*(1-period-slashes)^1*-1
+ if s==criterium then + return filename + end + end + end + return (n or filename).."."..suffix + end +end +local suffix=period*(1-period-slashes)^1*-1 local pattern=Cs((1-suffix)^0) -function file.replacesuffix(name,suffix)
- if name and suffix and suffix~="" then
- return lpegmatch(pattern,name).."."..suffix
- else
- return name
- end
+function file.replacesuffix(name,suffix) + if name and suffix and suffix~="" then + return lpegmatch(pattern,name).."."..suffix + else + return name + end end local reslasher=lpeg.replacer(P("\\"),"/") -function file.reslash(str)
- return str and lpegmatch(reslasher,str)
+function file.reslash(str) + return str and lpegmatch(reslasher,str) end -function file.is_writable(name)
+function file.is_writable(name) if not name then - elseif lfs.isdir(name) then
- name=name.."/m_t_x_t_e_s_t.tmp"
- local f=io.open(name,"wb")
- if f then
- f:close()
- os.remove(name)
- return true
- end
- elseif lfs.isfile(name) then
- local f=io.open(name,"ab")
- if f then
- f:close()
- return true
- end
- else
- local f=io.open(name,"ab")
- if f then
- f:close()
- os.remove(name)
- return true
- end
- end
- return false
+ elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true + end + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end + end + return false end local readable=P("r")*Cc(true) -function file.is_readable(name)
- if name then
- local a=attributes(name)
- return a and lpegmatch(readable,a.permissions) or false
- else
- return false
- end
+function file.is_readable(name) + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end file.isreadable=file.is_readable file.iswritable=file.is_writable -function file.size(name)
- if name then
- local a=attributes(name)
- return a and a.size or 0
- else
- return 0
- end
+function file.size(name) + if name then + local a=attributes(name) + return a and a.size or 0 + else + return 0 + end end function file.splitpath(str,separator) - return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator)
+ return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) end function file.joinpath(tab,separator) return tab and concat(tab,separator or io.pathseparator) end -local stripper=Cs(P(fwslash)^0/""*reslasher)
-local isnetwork=fwslash*fwslash*(1-fwslash)+(1-fwslash-colon)^1*colon
-local isroot=fwslash^1*-1
+local stripper=Cs(P(fwslash)^0/""*reslasher) +local isnetwork=fwslash*fwslash*(1-fwslash)+(1-fwslash-colon)^1*colon +local isroot=fwslash^1*-1 local hasroot=fwslash^1 local deslasher=lpeg.replacer(S("\\/")^1,"/") -function file.join(...)
- local lst={... }
- local one=lst[1]
- if lpegmatch(isnetwork,one) then
- local two=lpegmatch(deslasher,concat(lst,"/",2))
- return one.."/"..two
- elseif lpegmatch(isroot,one) then
- local two=lpegmatch(deslasher,concat(lst,"/",2))
- if lpegmatch(hasroot,two) then
- return two
- else
- return "/"..two
- end
- elseif one=="" then
- return lpegmatch(stripper,concat(lst,"/",2))
- else
- return lpegmatch(deslasher,concat(lst,"/"))
- end
-end -local drivespec=R("az","AZ")^1*colon
-local anchors=fwslash+drivespec
-local untouched=periods+(1-period)^1*P(-1)
-local splitstarter=(Cs(drivespec*(bwslash/"/"+fwslash)^0)+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
+function file.join(...) + local lst={... } + local one=lst[1] + if lpegmatch(isnetwork,one) then + local two=lpegmatch(deslasher,concat(lst,"/",2)) + return one.."/"..two + elseif lpegmatch(isroot,one) then + local two=lpegmatch(deslasher,concat(lst,"/",2)) + if lpegmatch(hasroot,two) then + return two + else + return "/"..two + end + elseif one=="" then + return lpegmatch(stripper,concat(lst,"/",2)) + else + return lpegmatch(deslasher,concat(lst,"/")) + end +end +local drivespec=R("az","AZ")^1*colon +local anchors=fwslash+drivespec +local untouched=periods+(1-period)^1*P(-1) +local splitstarter=(Cs(drivespec*(bwslash/"/"+fwslash)^0)+Cc(false))*Ct(lpeg.splitat(S("/\\")^1)) local absolute=fwslash function file.collapsepath(str,anchor) - if not str then
- return
- end
- if anchor==true and not lpegmatch(anchors,str) then
- str=getcurrentdir().."/"..str
- end
- if str=="" or str=="." then
- return "."
- elseif lpegmatch(untouched,str) then
- return lpegmatch(reslasher,str)
- end
- local starter,oldelements=lpegmatch(splitstarter,str)
- local newelements={}
- local i=#oldelements
- while i>0 do
- local element=oldelements[i]
+ if not str then + return + end + if anchor==true and not lpegmatch(anchors,str) then + str=getcurrentdir().."/"..str + end + if str=="" or str=="." then + return "." + elseif lpegmatch(untouched,str) then + return lpegmatch(reslasher,str) + end + local starter,oldelements=lpegmatch(splitstarter,str) + local newelements={} + local i=#oldelements + while i>0 do + local element=oldelements[i] if element=='.' then - elseif element=='..' then
- local n=i-1
- while n>0 do
- local element=oldelements[n]
- if element~='..' and element~='.' then
- oldelements[n]='.'
- break
- else
- n=n-1
- end
- end
- if n<1 then
- insert(newelements,1,'..')
- end
- elseif element~="" then
- insert(newelements,1,element)
- end
- i=i-1
- end
- if #newelements==0 then
- return starter or "."
- elseif starter then
- return starter..concat(newelements,'/')
- elseif lpegmatch(absolute,str) then
- return "/"..concat(newelements,'/')
- else
- newelements=concat(newelements,'/')
- if anchor=="." and find(str,"^%./") then
- return "./"..newelements
- else
- return newelements
- end
- end
-end -local validchars=R("az","09","AZ","--","..")
-local pattern_a=lpeg.replacer(1-validchars)
-local pattern_a=Cs((validchars+P(1)/"-")^1)
-local whatever=P("-")^0/""
+ elseif element=='..' then + local n=i-1 + while n>0 do + local element=oldelements[n] + if element~='..' and element~='.' then + oldelements[n]='.' + break + else + n=n-1 + end + end + if n<1 then + insert(newelements,1,'..') + end + elseif element~="" then + insert(newelements,1,element) + end + i=i-1 + end + if #newelements==0 then + return starter or "." + elseif starter then + return starter..concat(newelements,'/') + elseif lpegmatch(absolute,str) then + return "/"..concat(newelements,'/') + else + newelements=concat(newelements,'/') + if anchor=="." and find(str,"^%./") then + return "./"..newelements + else + return newelements + end + end +end +local validchars=R("az","09","AZ","--","..") +local pattern_a=lpeg.replacer(1-validchars) +local pattern_a=Cs((validchars+P(1)/"-")^1) +local whatever=P("-")^0/"" local pattern_b=Cs(whatever*(1-whatever*-1)^1) -function file.robustname(str,strict)
- if str then
- str=lpegmatch(pattern_a,str) or str
- if strict then
+function file.robustname(str,strict) + if str then + str=lpegmatch(pattern_a,str) or str + if strict then return lpegmatch(pattern_b,str) or str - else
- return str
- end
- end
+ else + return str + end + end end -file.readdata=io.loaddata
+file.readdata=io.loaddata file.savedata=io.savedata -function file.copy(oldname,newname)
- if oldname and newname then
- local data=io.loaddata(oldname)
- if data and data~="" then
- file.savedata(newname,data)
- end
- end
-end -local letter=R("az","AZ")+S("_-+")
+function file.copy(oldname,newname) + if oldname and newname then + local data=io.loaddata(oldname) + if data and data~="" then + file.savedata(newname,data) + end + end +end +local letter=R("az","AZ")+S("_-+") local separator=P("://") -local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash
+local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash local rootbased=fwslash+letter*colon -lpeg.patterns.qualified=qualified
+lpeg.patterns.qualified=qualified lpeg.patterns.rootbased=rootbased -function file.is_qualified_path(filename)
- return filename and lpegmatch(qualified,filename)~=nil
-end -function file.is_rootbased_path(filename)
- return filename and lpegmatch(rootbased,filename)~=nil
-end -function file.strip(name,dir)
- if name then
- local b,a=match(name,"^(.-)"..dir.."(.*)$")
- return a~="" and a or name
- end
-end -function lfs.mkdirs(path)
- local full
- for sub in gmatch(path,"([^\\/]+)") do
- if full then
- full=full.."/"..sub
- else
- full=sub
- end
- if not lfs.isdir(full) then
- lfs.mkdir(full)
- end
- end
-end
+function file.is_qualified_path(filename) + return filename and lpegmatch(qualified,filename)~=nil +end +function file.is_rootbased_path(filename) + return filename and lpegmatch(rootbased,filename)~=nil +end +function file.strip(name,dir) + if name then + local b,a=match(name,"^(.-)"..dir.."(.*)$") + return a~="" and a or name + end +end +function lfs.mkdirs(path) + local full + for sub in gmatch(path,"([^\\/]+)") do + if full then + full=full.."/"..sub + else + full=sub + end + if not lfs.isdir(full) then + lfs.mkdir(full) + end + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-boolean']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-boolean']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber=type,tonumber -boolean=boolean or {}
+boolean=boolean or {} local boolean=boolean -function boolean.tonumber(b)
+function boolean.tonumber(b) if b then return 1 else return 0 end end function toboolean(str,tolerant) - if str==nil then
- return false
- elseif str==false then
- return false
- elseif str==true then
- return true
- elseif str=="true" then
- return true
- elseif str=="false" then
- return false
- elseif not tolerant then
- return false
- elseif str==0 then
- return false
- elseif (tonumber(str) or 0)>0 then
- return true
- else
- return str=="yes" or str=="on" or str=="t"
- end
+ if str==nil then + return false + elseif str==false then + return false + elseif str==true then + return true + elseif str=="true" then + return true + elseif str=="false" then + return false + elseif not tolerant then + return false + elseif str==0 then + return false + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end string.toboolean=toboolean -function string.booleanstring(str)
- if str=="0" then
- return false
- elseif str=="1" then
- return true
- elseif str=="" then
- return false
- elseif str=="false" then
- return false
- elseif str=="true" then
- return true
- elseif (tonumber(str) or 0)>0 then
- return true
- else
- return str=="yes" or str=="on" or str=="t"
- end
-end -function string.is_boolean(str,default)
- if type(str)=="string" then
- if str=="true" or str=="yes" or str=="on" or str=="t" then
- return true
- elseif str=="false" or str=="no" or str=="off" or str=="f" then
- return false
- end
- end
- return default
-end
+function string.booleanstring(str) + if str=="0" then + return false + elseif str=="1" then + return true + elseif str=="" then + return false + elseif str=="false" then + return false + elseif str=="true" then + return true + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end +end +function string.is_boolean(str,default) + if type(str)=="string" then + if str=="true" or str=="yes" or str=="on" or str=="t" then + return true + elseif str=="false" or str=="no" or str=="off" or str=="f" then + return false + end + end + return default +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-math']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['l-math']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local floor,sin,cos,tan=math.floor,math.sin,math.cos,math.tan -if not math.round then
- function math.round(x) return floor(x+0.5) end
+if not math.round then + function math.round(x) return floor(x+0.5) end end -if not math.div then
- function math.div(n,m) return floor(n/m) end
+if not math.div then + function math.div(n,m) return floor(n/m) end end -if not math.mod then
- function math.mod(n,m) return n%m end
+if not math.mod then + function math.mod(n,m) return n%m end end local pipi=2*math.pi/360 -if not math.sind then
- function math.sind(d) return sin(d*pipi) end
- function math.cosd(d) return cos(d*pipi) end
- function math.tand(d) return tan(d*pipi) end
-end -if not math.odd then
- function math.odd (n) return n%2~=0 end
- function math.even(n) return n%2==0 end
-end
+if not math.sind then + function math.sind(d) return sin(d*pipi) end + function math.cosd(d) return cos(d*pipi) end + function math.tand(d) return tan(d*pipi) end +end +if not math.odd then + function math.odd (n) return n%2~=0 end + function math.even(n) return n%2==0 end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['util-str']={
- version=1.001,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['util-str']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -utilities=utilities or {}
-utilities.strings=utilities.strings or {}
+utilities=utilities or {} +utilities.strings=utilities.strings or {} local strings=utilities.strings -local format,gsub,rep,sub=string.format,string.gsub,string.rep,string.sub
-local load,dump=load,string.dump
-local tonumber,type,tostring=tonumber,type,tostring
-local unpack,concat=table.unpack,table.concat
-local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
-local patterns,lpegmatch=lpeg.patterns,lpeg.match
+local format,gsub,rep,sub=string.format,string.gsub,string.rep,string.sub +local load,dump=load,string.dump +local tonumber,type,tostring=tonumber,type,tostring +local unpack,concat=table.unpack,table.concat +local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc +local patterns,lpegmatch=lpeg.patterns,lpeg.match local utfchar,utfbyte=utf.char,utf.byte -local loadstripped=_LUAVERSION<5.2 and load or function(str)
+local loadstripped=_LUAVERSION<5.2 and load or function(str) return load(dump(load(str),true)) end if not number then number={} end local stripper=patterns.stripzeros -local function points(n)
- return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
+local function points(n) + return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) end -local function basepoints(n)
- return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536))
+local function basepoints(n) + return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536)) end -number.points=points
+number.points=points number.basepoints=basepoints -local rubish=patterns.spaceortab^0*patterns.newline
-local anyrubish=patterns.spaceortab+patterns.newline
-local anything=patterns.anything
-local stripped=(patterns.spaceortab^1/"")*patterns.newline
-local leading=rubish^0/""
-local trailing=(anyrubish^1*patterns.endofstring)/""
+local rubish=patterns.spaceortab^0*patterns.newline +local anyrubish=patterns.spaceortab+patterns.newline +local anything=patterns.anything +local stripped=(patterns.spaceortab^1/"")*patterns.newline +local leading=rubish^0/"" +local trailing=(anyrubish^1*patterns.endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) -function strings.collapsecrlf(str)
- return lpegmatch(pattern,str)
+function strings.collapsecrlf(str) + return lpegmatch(pattern,str) end local repeaters={} -function strings.newrepeater(str,offset)
- offset=offset or 0
- local s=repeaters[str]
- if not s then
- s={}
- repeaters[str]=s
- end
- local t=s[offset]
- if t then
- return t
- end
- t={}
- setmetatable(t,{ __index=function(t,k)
- if not k then
- return ""
- end
- local n=k+offset
- local s=n>0 and rep(str,n) or ""
- t[k]=s
- return s
- end })
- s[offset]=t
- return t
+function strings.newrepeater(str,offset) + offset=offset or 0 + local s=repeaters[str] + if not s then + s={} + repeaters[str]=s + end + local t=s[offset] + if t then + return t + end + t={} + setmetatable(t,{ __index=function(t,k) + if not k then + return "" + end + local n=k+offset + local s=n>0 and rep(str,n) or "" + t[k]=s + return s + end }) + s[offset]=t + return t end local extra,tab,start=0,0,4,0 local nspaces=strings.newrepeater(" ") string.nspaces=nspaces -local pattern=Carg(1)/function(t)
- extra,tab,start=0,t or 7,1
- end*Cs((
- Cp()*patterns.tab/function(position)
- local current=(position-start+1)+extra
- local spaces=tab-(current-1)%tab
- if spaces>0 then
- extra=extra+spaces-1
+local pattern=Carg(1)/function(t) + extra,tab,start=0,t or 7,1 + end*Cs(( + Cp()*patterns.tab/function(position) + local current=(position-start+1)+extra + local spaces=tab-(current-1)%tab + if spaces>0 then + extra=extra+spaces-1 return nspaces[spaces] - else
- return ""
- end
- end+patterns.newline*Cp()/function(position)
- extra,start=0,position
- end+patterns.anything
+ else + return "" + end + end+patterns.newline*Cp()/function(position) + extra,start=0,position + end+patterns.anything )^1) -function strings.tabtospace(str,tab)
- return lpegmatch(pattern,str,1,tab or 7)
+function strings.tabtospace(str,tab) + return lpegmatch(pattern,str,1,tab or 7) end function strings.striplong(str) - str=gsub(str,"^%s*","")
- str=gsub(str,"[\n\r]+ *","\n")
- return str
+ str=gsub(str,"^%s*","") + str=gsub(str,"[\n\r]+ *","\n") + return str end -function strings.nice(str)
+function strings.nice(str) str=gsub(str,"[:%-+_]+"," ") - return str
+ return str end local n=0 local sequenced=table.sequenced -function string.autodouble(s,sep)
- if s==nil then
- return '""'
- end
- local t=type(s)
- if t=="number" then
+function string.autodouble(s,sep) + if s==nil then + return '""' + end + local t=type(s) + if t=="number" then return tostring(s) - end
- if t=="table" then
- return ('"'..sequenced(s,sep or ",")..'"')
- end
- return ('"'..tostring(s)..'"')
-end -function string.autosingle(s,sep)
- if s==nil then
- return "''"
- end
- local t=type(s)
- if t=="number" then
+ end + if t=="table" then + return ('"'..sequenced(s,sep or ",")..'"') + end + return ('"'..tostring(s)..'"') +end +function string.autosingle(s,sep) + if s==nil then + return "''" + end + local t=type(s) + if t=="number" then return tostring(s) - end
- if t=="table" then
- return ("'"..sequenced(s,sep or ",").."'")
- end
- return ("'"..tostring(s).."'")
-end -local tracedchars={}
-string.tracedchars=tracedchars
+ end + if t=="table" then + return ("'"..sequenced(s,sep or ",").."'") + end + return ("'"..tostring(s).."'") +end +local tracedchars={} +string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) - if type(b)=="number" then
- return tracedchars[b] or (utfchar(b).." (U+"..format('%05X',b)..")")
- else
- local c=utfbyte(b)
- return tracedchars[c] or (b.." (U+"..format('%05X',c)..")")
- end
-end -function number.signed(i)
- if i>0 then
- return "+",i
- else
- return "-",-i
- end
-end -local preamble=[[
-local type = type
-local tostring = tostring
-local tonumber = tonumber
-local format = string.format
-local concat = table.concat
-local signed = number.signed
-local points = number.points
-local basepoints = number.basepoints
-local utfchar = utf.char
-local utfbyte = utf.byte
-local lpegmatch = lpeg.match
-local nspaces = string.nspaces
-local tracedchar = string.tracedchar
-local autosingle = string.autosingle
-local autodouble = string.autodouble
-local sequenced = table.sequenced
+ if type(b)=="number" then + return tracedchars[b] or (utfchar(b).." (U+"..format('%05X',b)..")") + else + local c=utfbyte(b) + return tracedchars[c] or (b.." (U+"..format('%05X',c)..")") + end +end +function number.signed(i) + if i>0 then + return "+",i + else + return "-",-i + end +end +local preamble=[[ +local type = type +local tostring = tostring +local tonumber = tonumber +local format = string.format +local concat = table.concat +local signed = number.signed +local points = number.points +local basepoints = number.basepoints +local utfchar = utf.char +local utfbyte = utf.byte +local lpegmatch = lpeg.match +local nspaces = string.nspaces +local tracedchar = string.tracedchar +local autosingle = string.autosingle +local autodouble = string.autodouble +local sequenced = table.sequenced ]] -local template=[[
-%s
-%s
-return function(%s) return %s end
+local template=[[ +%s +%s +return function(%s) return %s end ]] local arguments={ "a1" } -setmetatable(arguments,{ __index=function(t,k)
- local v=t[k-1]..",a"..k
- t[k]=v
- return v
- end
+setmetatable(arguments,{ __index=function(t,k) + local v=t[k-1]..",a"..k + t[k]=v + return v + end }) -local prefix_any=C((S("+- .")+R("09"))^0)
+local prefix_any=C((S("+- .")+R("09"))^0) local prefix_tab=C((1-R("az","AZ","09","%%"))^0) -local format_s=function(f)
- n=n+1
- if f and f~="" then
- return format("format('%%%ss',a%s)",f,n)
+local format_s=function(f) + n=n+1 + if f and f~="" then + return format("format('%%%ss',a%s)",f,n) else return format("(a%s or '')",n) - end
+ end end local format_S=function(f) - n=n+1
- if f and f~="" then
- return format("format('%%%ss',tostring(a%s))",f,n)
- else
- return format("tostring(a%s)",n)
- end
-end -local format_q=function()
- n=n+1
+ n=n+1 + if f and f~="" then + return format("format('%%%ss',tostring(a%s))",f,n) + else + return format("tostring(a%s)",n) + end +end +local format_q=function() + n=n+1 return format("(a%s and format('%%q',a%s) or '')",n,n) end local format_Q=function() - n=n+1
- return format("format('%%q',tostring(a%s))",n)
+ n=n+1 + return format("format('%%q',tostring(a%s))",n) end -local format_i=function(f)
- n=n+1
- if f and f~="" then
- return format("format('%%%si',a%s)",f,n)
- else
- return format("a%s",n)
- end
+local format_i=function(f) + n=n+1 + if f and f~="" then + return format("format('%%%si',a%s)",f,n) + else + return format("a%s",n) + end end local format_d=format_i -local format_I=function(f)
- n=n+1
- return format("format('%%s%%%si',signed(a%s))",f,n)
-end -local format_f=function(f)
- n=n+1
- return format("format('%%%sf',a%s)",f,n)
-end -local format_g=function(f)
- n=n+1
- return format("format('%%%sg',a%s)",f,n)
-end -local format_G=function(f)
- n=n+1
- return format("format('%%%sG',a%s)",f,n)
-end -local format_e=function(f)
- n=n+1
- return format("format('%%%se',a%s)",f,n)
-end -local format_E=function(f)
- n=n+1
- return format("format('%%%sE',a%s)",f,n)
-end -local format_x=function(f)
- n=n+1
- return format("format('%%%sx',a%s)",f,n)
-end -local format_X=function(f)
- n=n+1
- return format("format('%%%sX',a%s)",f,n)
-end -local format_o=function(f)
- n=n+1
- return format("format('%%%so',a%s)",f,n)
-end -local format_c=function()
- n=n+1
- return format("utfchar(a%s)",n)
-end -local format_C=function()
- n=n+1
- return format("tracedchar(a%s)",n)
-end -local format_r=function(f)
- n=n+1
- return format("format('%%%s.0f',a%s)",f,n)
-end -local format_h=function(f)
- n=n+1
- if f=="-" then
- f=sub(f,2)
- return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- else
- return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- end
-end -local format_H=function(f)
- n=n+1
- if f=="-" then
- f=sub(f,2)
- return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- else
- return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- end
-end -local format_u=function(f)
- n=n+1
- if f=="-" then
- f=sub(f,2)
- return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- else
- return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- end
-end -local format_U=function(f)
- n=n+1
- if f=="-" then
- f=sub(f,2)
- return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- else
- return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
- end
-end -local format_p=function()
- n=n+1
- return format("points(a%s)",n)
-end -local format_b=function()
- n=n+1
- return format("basepoints(a%s)",n)
-end -local format_t=function(f)
- n=n+1
- if f and f~="" then
- return format("concat(a%s,%q)",n,f)
- else
- return format("concat(a%s)",n)
- end
-end -local format_T=function(f)
- n=n+1
- if f and f~="" then
- return format("sequenced(a%s,%q)",n,f)
- else
- return format("sequenced(a%s)",n)
- end
-end -local format_l=function()
- n=n+1
- return format("(a%s and 'true' or 'false')",n)
-end -local format_L=function()
- n=n+1
- return format("(a%s and 'TRUE' or 'FALSE')",n)
+local format_I=function(f) + n=n+1 + return format("format('%%s%%%si',signed(a%s))",f,n) +end +local format_f=function(f) + n=n+1 + return format("format('%%%sf',a%s)",f,n) +end +local format_g=function(f) + n=n+1 + return format("format('%%%sg',a%s)",f,n) +end +local format_G=function(f) + n=n+1 + return format("format('%%%sG',a%s)",f,n) +end +local format_e=function(f) + n=n+1 + return format("format('%%%se',a%s)",f,n) +end +local format_E=function(f) + n=n+1 + return format("format('%%%sE',a%s)",f,n) +end +local format_x=function(f) + n=n+1 + return format("format('%%%sx',a%s)",f,n) +end +local format_X=function(f) + n=n+1 + return format("format('%%%sX',a%s)",f,n) +end +local format_o=function(f) + n=n+1 + return format("format('%%%so',a%s)",f,n) +end +local format_c=function() + n=n+1 + return format("utfchar(a%s)",n) +end +local format_C=function() + n=n+1 + return format("tracedchar(a%s)",n) +end +local format_r=function(f) + n=n+1 + return format("format('%%%s.0f',a%s)",f,n) +end +local format_h=function(f) + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end +end +local format_H=function(f) + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end +end +local format_u=function(f) + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end +end +local format_U=function(f) + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end +end +local format_p=function() + n=n+1 + return format("points(a%s)",n) +end +local format_b=function() + n=n+1 + return format("basepoints(a%s)",n) +end +local format_t=function(f) + n=n+1 + if f and f~="" then + return format("concat(a%s,%q)",n,f) + else + return format("concat(a%s)",n) + end +end +local format_T=function(f) + n=n+1 + if f and f~="" then + return format("sequenced(a%s,%q)",n,f) + else + return format("sequenced(a%s)",n) + end +end +local format_l=function() + n=n+1 + return format("(a%s and 'true' or 'false')",n) +end +local format_L=function() + n=n+1 + return format("(a%s and 'TRUE' or 'FALSE')",n) end local format_N=function() - n=n+1
- return format("tostring(tonumber(a%s) or a%s)",n,n)
-end -local format_a=function(f)
- n=n+1
- if f and f~="" then
- return format("autosingle(a%s,%q)",n,f)
- else
- return format("autosingle(a%s)",n)
- end
-end -local format_A=function(f)
- n=n+1
- if f and f~="" then
- return format("autodouble(a%s,%q)",n,f)
- else
- return format("autodouble(a%s)",n)
- end
+ n=n+1 + return format("tostring(tonumber(a%s) or a%s)",n,n) +end +local format_a=function(f) + n=n+1 + if f and f~="" then + return format("autosingle(a%s,%q)",n,f) + else + return format("autosingle(a%s)",n) + end +end +local format_A=function(f) + n=n+1 + if f and f~="" then + return format("autodouble(a%s,%q)",n,f) + else + return format("autodouble(a%s)",n) + end end local format_w=function(f) - n=n+1
- f=tonumber(f)
+ n=n+1 + f=tonumber(f) if f then return format("nspaces[%s+a%s]",f,n) - else
+ else return format("nspaces[a%s]",n) - end
+ end end local format_W=function(f) - return format("nspaces[%s]",tonumber(f) or 0)
+ return format("nspaces[%s]",tonumber(f) or 0) end -local format_rest=function(s)
+local format_rest=function(s) return format("%q",s) end -local format_extension=function(extensions,f,name)
- local extension=extensions[name] or "tostring(%s)"
- local f=tonumber(f) or 1
- if f==0 then
- return extension
- elseif f==1 then
- n=n+1
- local a="a"..n
+local format_extension=function(extensions,f,name) + local extension=extensions[name] or "tostring(%s)" + local f=tonumber(f) or 1 + if f==0 then + return extension + elseif f==1 then + n=n+1 + local a="a"..n return format(extension,a,a) - elseif f<0 then
- local a="a"..(n+f+1)
- return format(extension,a,a)
- else
- local t={}
- for i=1,f do
- n=n+1
- t[#t+1]="a"..n
- end
- return format(extension,unpack(t))
- end
-end -local builder=Cs { "start",
- start=(
- (
- P("%")/""*(
+ elseif f<0 then + local a="a"..(n+f+1) + return format(extension,a,a) + else + local t={} + for i=1,f do + n=n+1 + t[#t+1]="a"..n + end + return format(extension,unpack(t)) + end +end +local builder=Cs { "start", + start=( + ( + P("%")/""*( V("!") +V("s")+V("q")+V("i")+V("d")+V("f")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o") +V("c")+V("C")+V("S") @@ -2811,8 +2811,8 @@ local builder=Cs { "start", +V("a") +V("A") +V("*") - )+V("*")
- )*(P(-1)+Carg(1))
+ )+V("*") + )*(P(-1)+Carg(1)) )^0, ["s"]=(prefix_any*P("s"))/format_s, ["q"]=(prefix_any*P("q"))/format_q, @@ -2848,796 +2848,796 @@ local builder=Cs { "start", ["a"]=(prefix_any*P("a"))/format_a, ["A"]=(prefix_any*P("A"))/format_A, ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%%%")^1)/format_rest, - ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
+ ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } -local direct=Cs (
- P("%")/""*Cc([[local format = string.format return function(str) return format("%]])*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*Cc([[",str) end]])*P(-1)
+local direct=Cs ( + P("%")/""*Cc([[local format = string.format return function(str) return format("%]])*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*Cc([[",str) end]])*P(-1) ) -local function make(t,str)
- local f
- local p
- local p=lpegmatch(direct,str)
- if p then
- f=loadstripped(p)()
- else
- n=0
+local function make(t,str) + local f + local p + local p=lpegmatch(direct,str) + if p then + f=loadstripped(p)() + else + n=0 p=lpegmatch(builder,str,1,"..",t._extensions_) - if n>0 then
+ if n>0 then p=format(template,preamble,t._preamble_,arguments[n],p) - f=loadstripped(p)()
- else
- f=function() return str end
- end
- end
- t[str]=f
- return f
+ f=loadstripped(p)() + else + f=function() return str end + end + end + t[str]=f + return f end -local function use(t,fmt,...)
- return t[fmt](...)
+local function use(t,fmt,...) + return t[fmt](...) end strings.formatters={} -function strings.formatters.new()
- local t={ _extensions_={},_preamble_="",_type_="formatter" }
- setmetatable(t,{ __index=make,__call=use })
- return t
+function strings.formatters.new() + local t={ _extensions_={},_preamble_="",_type_="formatter" } + setmetatable(t,{ __index=make,__call=use }) + return t end local formatters=strings.formatters.new() string.formatters=formatters string.formatter=function(str,...) return formatters[str](...) end -local function add(t,name,template,preamble)
- if type(t)=="table" and t._type_=="formatter" then
- t._extensions_[name]=template or "%s"
- if preamble then
+local function add(t,name,template,preamble) + if type(t)=="table" and t._type_=="formatter" then + t._extensions_[name]=template or "%s" + if preamble then t._preamble_=preamble.."\n"..t._preamble_ - end
- end
+ end + end end strings.formatters.add=add -lpeg.patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0)
+lpeg.patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) lpeg.patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]])
+add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]]) add(formatters,"tex",[[lpegmatch(texescape,%s)]],[[local texescape = lpeg.patterns.texescape]]) end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luat-basics-gen']={
- version=1.100,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luat-basics-gen']={ + version=1.100, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end -local dummyfunction=function()
-end -local dummyreporter=function(c)
- return function(...)
- (texio.reporter or texio.write_nl)(c.." : "..string.formatters(...))
- end
-end -statistics={
- register=dummyfunction,
- starttiming=dummyfunction,
- stoptiming=dummyfunction,
- elapsedtime=nil,
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end +local dummyfunction=function() +end +local dummyreporter=function(c) + return function(...) + (texio.reporter or texio.write_nl)(c.." : "..string.formatters(...)) + end +end +statistics={ + register=dummyfunction, + starttiming=dummyfunction, + stoptiming=dummyfunction, + elapsedtime=nil, } -directives={
- register=dummyfunction,
- enable=dummyfunction,
- disable=dummyfunction,
+directives={ + register=dummyfunction, + enable=dummyfunction, + disable=dummyfunction, } -trackers={
- register=dummyfunction,
- enable=dummyfunction,
- disable=dummyfunction,
+trackers={ + register=dummyfunction, + enable=dummyfunction, + disable=dummyfunction, } -experiments={
- register=dummyfunction,
- enable=dummyfunction,
- disable=dummyfunction,
+experiments={ + register=dummyfunction, + enable=dummyfunction, + disable=dummyfunction, } storage={ - register=dummyfunction,
- shared={},
+ register=dummyfunction, + shared={}, } -logs={
- new=dummyreporter,
- reporter=dummyreporter,
- messenger=dummyreporter,
- report=dummyfunction,
+logs={ + new=dummyreporter, + reporter=dummyreporter, + messenger=dummyreporter, + report=dummyfunction, } -callbacks={
+callbacks={ register=function(n,f) return callback.register(n,f) end, } -utilities={
- storage={
- allocate=function(t) return t or {} end,
- mark=function(t) return t or {} end,
- },
+utilities={ + storage={ + allocate=function(t) return t or {} end, + mark=function(t) return t or {} end, + }, } -characters=characters or {
- data={}
+characters=characters or { + data={} } texconfig.kpse_init=true resolvers=resolvers or {} -local remapper={
- otf="opentype fonts",
- ttf="truetype fonts",
- ttc="truetype fonts",
+local remapper={ + otf="opentype fonts", + ttf="truetype fonts", + ttc="truetype fonts", dfont="truetype fonts", - cid="cid maps",
- cidmap="cid maps",
- fea="font feature files",
+ cid="cid maps", + cidmap="cid maps", + fea="font feature files", pfa="type1 fonts", pfb="type1 fonts", } -function resolvers.findfile(name,fileformat)
- name=string.gsub(name,"\\","/")
- if not fileformat or fileformat=="" then
- fileformat=file.suffix(name)
- if fileformat=="" then
- fileformat="tex"
- end
- end
- fileformat=string.lower(fileformat)
- fileformat=remapper[fileformat] or fileformat
- local found=kpse.find_file(name,fileformat)
- if not found or found=="" then
- found=kpse.find_file(name,"other text files")
- end
- return found
+function resolvers.findfile(name,fileformat) + name=string.gsub(name,"\\","/") + if not fileformat or fileformat=="" then + fileformat=file.suffix(name) + if fileformat=="" then + fileformat="tex" + end + end + fileformat=string.lower(fileformat) + fileformat=remapper[fileformat] or fileformat + local found=kpse.find_file(name,fileformat) + if not found or found=="" then + found=kpse.find_file(name,"other text files") + end + return found end resolvers.findbinfile=resolvers.findfile -function resolvers.resolve(s)
- return s
+function resolvers.resolve(s) + return s end -function resolvers.unresolve(s)
- return s
+function resolvers.unresolve(s) + return s end caches={} -local writable=nil
-local readables={}
+local writable=nil +local readables={} local usingjit=jit -if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then
- caches.namespace='generic'
+if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then + caches.namespace='generic' end do local cachepaths=kpse.expand_path('$TEXMFCACHE') or "" - if cachepaths=="" then
- cachepaths=kpse.expand_path('$TEXMFVAR')
+ if cachepaths=="" then + cachepaths=kpse.expand_path('$TEXMFVAR') end - if cachepaths=="" then
- cachepaths=kpse.expand_path('$VARTEXMF')
+ if cachepaths=="" then + cachepaths=kpse.expand_path('$VARTEXMF') end - if cachepaths=="" then
- cachepaths="."
+ if cachepaths=="" then + cachepaths="." end cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":") - for i=1,#cachepaths do
- local cachepath=cachepaths[i]
- if not lfs.isdir(cachepath) then
+ for i=1,#cachepaths do + local cachepath=cachepaths[i] + if not lfs.isdir(cachepath) then lfs.mkdirs(cachepath) - if lfs.isdir(cachepath) then
- texio.write(string.format("(created cache path: %s)",cachepath))
- end
- end
- if file.is_writable(cachepath) then
- writable=file.join(cachepath,"luatex-cache")
- lfs.mkdir(writable)
- writable=file.join(writable,caches.namespace)
- lfs.mkdir(writable)
- break
- end
- end - for i=1,#cachepaths do
- if file.is_readable(cachepaths[i]) then
- readables[#readables+1]=file.join(cachepaths[i],"luatex-cache",caches.namespace)
- end
- end - if not writable then
- texio.write_nl("quiting: fix your writable cache path")
- os.exit()
- elseif #readables==0 then
- texio.write_nl("quiting: fix your readable cache path")
- os.exit()
- elseif #readables==1 and readables[1]==writable then
- texio.write(string.format("(using cache: %s)",writable))
- else
- texio.write(string.format("(using write cache: %s)",writable))
- texio.write(string.format("(using read cache: %s)",table.concat(readables," ")))
- end -end -function caches.getwritablepath(category,subcategory)
- local path=file.join(writable,category)
- lfs.mkdir(path)
- path=file.join(path,subcategory)
- lfs.mkdir(path)
- return path
-end -function caches.getreadablepaths(category,subcategory)
- local t={}
- for i=1,#readables do
- t[i]=file.join(readables[i],category,subcategory)
- end
- return t
-end -local function makefullname(path,name)
- if path and path~="" then
- return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc")
- end
-end -function caches.is_writable(path,name)
- local fullname=makefullname(path,name)
- return fullname and file.is_writable(fullname)
-end -function caches.loaddata(paths,name)
- for i=1,#paths do
- local data=false
- local luaname,lucname=makefullname(paths[i],name)
+ if lfs.isdir(cachepath) then + texio.write(string.format("(created cache path: %s)",cachepath)) + end + end + if file.is_writable(cachepath) then + writable=file.join(cachepath,"luatex-cache") + lfs.mkdir(writable) + writable=file.join(writable,caches.namespace) + lfs.mkdir(writable) + break + end + end + for i=1,#cachepaths do + if file.is_readable(cachepaths[i]) then + readables[#readables+1]=file.join(cachepaths[i],"luatex-cache",caches.namespace) + end + end + if not writable then + texio.write_nl("quiting: fix your writable cache path") + os.exit() + elseif #readables==0 then + texio.write_nl("quiting: fix your readable cache path") + os.exit() + elseif #readables==1 and readables[1]==writable then + texio.write(string.format("(using cache: %s)",writable)) + else + texio.write(string.format("(using write cache: %s)",writable)) + texio.write(string.format("(using read cache: %s)",table.concat(readables," "))) + end +end +function caches.getwritablepath(category,subcategory) + local path=file.join(writable,category) + lfs.mkdir(path) + path=file.join(path,subcategory) + lfs.mkdir(path) + return path +end +function caches.getreadablepaths(category,subcategory) + local t={} + for i=1,#readables do + t[i]=file.join(readables[i],category,subcategory) + end + return t +end +local function makefullname(path,name) + if path and path~="" then + return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc") + end +end +function caches.is_writable(path,name) + local fullname=makefullname(path,name) + return fullname and file.is_writable(fullname) +end +function caches.loaddata(paths,name) + for i=1,#paths do + local data=false + local luaname,lucname=makefullname(paths[i],name) if lucname and lfs.isfile(lucname) then - texio.write(string.format("(load luc: %s)",lucname))
- data=loadfile(lucname)
- if data then
- data=data()
- end
- if data then
- return data
- else
- texio.write(string.format("(loading failed: %s)",lucname))
- end
- end
- if luaname and lfs.isfile(luaname) then
- texio.write(string.format("(load lua: %s)",luaname))
- data=loadfile(luaname)
- if data then
- data=data()
- end
- if data then
- return data
- end
- end
- end
-end -function caches.savedata(path,name,data)
- local luaname,lucname=makefullname(path,name)
- if luaname then
- texio.write(string.format("(save: %s)",luaname))
- table.tofile(luaname,data,true,{ reduce=true })
- if lucname and type(caches.compile)=="function" then
+ texio.write(string.format("(load luc: %s)",lucname)) + data=loadfile(lucname) + if data then + data=data() + end + if data then + return data + else + texio.write(string.format("(loading failed: %s)",lucname)) + end + end + if luaname and lfs.isfile(luaname) then + texio.write(string.format("(load lua: %s)",luaname)) + data=loadfile(luaname) + if data then + data=data() + end + if data then + return data + end + end + end +end +function caches.savedata(path,name,data) + local luaname,lucname=makefullname(path,name) + if luaname then + texio.write(string.format("(save: %s)",luaname)) + table.tofile(luaname,data,true,{ reduce=true }) + if lucname and type(caches.compile)=="function" then os.remove(lucname) - texio.write(string.format("(save: %s)",lucname))
- caches.compile(data,luaname,lucname)
- end
- end
-end -function caches.compile(data,luaname,lucname)
- local d=io.loaddata(luaname)
- if not d or d=="" then
+ texio.write(string.format("(save: %s)",lucname)) + caches.compile(data,luaname,lucname) + end + end +end +function caches.compile(data,luaname,lucname) + local d=io.loaddata(luaname) + if not d or d=="" then d=table.serialize(data,true) - end
- if d and d~="" then
- local f=io.open(lucname,'wb')
- if f then
- local s=loadstring(d)
- if s then
- f:write(string.dump(s,true))
- end
- f:close()
- end
- end
-end -function table.setmetatableindex(t,f)
- setmetatable(t,{ __index=f })
-end
+ end + if d and d~="" then + local f=io.open(lucname,'wb') + if f then + local s=loadstring(d) + if s then + f:write(string.dump(s,true)) + end + f:close() + end + end +end +function table.setmetatableindex(t,f) + setmetatable(t,{ __index=f }) +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['data-con']={
- version=1.100,
- comment="companion to luat-lib.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['data-con']={ + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end)
-local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end)
+local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) -containers=containers or {}
-local containers=containers
+containers=containers or {} +local containers=containers containers.usecache=true local report_containers=logs.reporter("resolvers","containers") local allocated={} -local mt={
- __index=function(t,k)
- if k=="writable" then
- local writable=caches.getwritablepath(t.category,t.subcategory) or { "." }
- t.writable=writable
- return writable
- elseif k=="readables" then
- local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." }
- t.readables=readables
- return readables
- end
- end,
- __storage__=true
+local mt={ + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true } -function containers.define(category,subcategory,version,enabled)
- if category and subcategory then
- local c=allocated[category]
- if not c then
- c={}
- allocated[category]=c
- end
- local s=c[subcategory]
- if not s then
- s={
- category=category,
- subcategory=subcategory,
- storage={},
- enabled=enabled,
+function containers.define(category,subcategory,version,enabled) + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, version=version or math.pi, trace=false, - }
- setmetatable(s,mt)
- c[subcategory]=s
- end
- return s
- end
-end -function containers.is_usable(container,name)
- return container.enabled and caches and caches.is_writable(container.writable,name)
-end -function containers.is_valid(container,name)
- if name and name~="" then
- local storage=container.storage[name]
- return storage and storage.cache_version==container.version
- else
- return false
- end
-end -function containers.read(container,name)
- local storage=container.storage
- local stored=storage[name]
- if not stored and container.enabled and caches and containers.usecache then
- stored=caches.loaddata(container.readables,name)
- if stored and stored.cache_version==container.version then
- if trace_cache or trace_containers then
- report_containers("action %a, category %a, name %a","load",container.subcategory,name)
- end
- else
- stored=nil
- end
- storage[name]=stored
- elseif stored then
- if trace_cache or trace_containers then
- report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
- end
- end
- return stored
-end -function containers.write(container,name,data)
- if data then
- data.cache_version=container.version
- if container.enabled and caches then
- local unique,shared=data.unique,data.shared
- data.unique,data.shared=nil,nil
- caches.savedata(container.writable,name,data)
- if trace_cache or trace_containers then
- report_containers("action %a, category %a, name %a","save",container.subcategory,name)
- end
- data.unique,data.shared=unique,shared
- end
- if trace_cache or trace_containers then
- report_containers("action %a, category %a, name %a","store",container.subcategory,name)
- end
- container.storage[name]=data
- end
- return data
-end -function containers.content(container,name)
- return container.storage[name]
+ } + setmetatable(s,mt) + c[subcategory]=s + end + return s + end +end +function containers.is_usable(container,name) + return container.enabled and caches and caches.is_writable(container.writable,name) +end +function containers.is_valid(container,name) + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end +end +function containers.read(container,name) + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil + end + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored +end +function containers.write(container,name,data) + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared + end + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data +end +function containers.content(container,name) + return container.storage[name] end function containers.cleanname(name) return (gsub(lower(name),"[^%w\128-\255]+","-")) -end
+end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-nod']={
- version=1.001,
- comment="companion to luatex-fonts.lua",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-nod']={ + version=1.001, + comment="companion to luatex-fonts.lua", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end if tex.attribute[0]~=0 then - texio.write_nl("log","!")
- texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
- texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
- texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
+ texio.write_nl("log","!") + texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") + texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") + texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.") texio.write_nl("log","!") tex.attribute[0]=0 end -attributes=attributes or {}
+attributes=attributes or {} attributes.unsetvalue=-0x7FFFFFFF local numbers,last={},127 -attributes.private=attributes.private or function(name)
- local number=numbers[name]
- if not number then
- if last<255 then
- last=last+1
- end
- number=last
- numbers[name]=number
- end
- return number
-end -nodes={}
-nodes.pool={}
+attributes.private=attributes.private or function(name) + local number=numbers[name] + if not number then + if last<255 then + last=last+1 + end + number=last + numbers[name]=number + end + return number +end +nodes={} +nodes.pool={} nodes.handlers={} -local nodecodes={} for k,v in next,node.types () do nodecodes[string.gsub(v,"_","")]=k end
-local whatcodes={} for k,v in next,node.whatsits() do whatcodes[string.gsub(v,"_","")]=k end
+local nodecodes={} for k,v in next,node.types () do nodecodes[string.gsub(v,"_","")]=k end +local whatcodes={} for k,v in next,node.whatsits() do whatcodes[string.gsub(v,"_","")]=k end local glyphcodes={ [0]="character","glyph","ligature","ghost","left","right" } -nodes.nodecodes=nodecodes
-nodes.whatcodes=whatcodes
-nodes.whatsitcodes=whatcodes
+nodes.nodecodes=nodecodes +nodes.whatcodes=whatcodes +nodes.whatsitcodes=whatcodes nodes.glyphcodes=glyphcodes -local free_node=node.free
-local remove_node=node.remove
-local new_node=node.new
+local free_node=node.free +local remove_node=node.remove +local new_node=node.new local traverse_id=node.traverse_id local math_code=nodecodes.math -nodes.handlers.protectglyphs=node.protect_glyphs
+nodes.handlers.protectglyphs=node.protect_glyphs nodes.handlers.unprotectglyphs=node.unprotect_glyphs -function nodes.remove(head,current,free_too)
- local t=current
- head,current=remove_node(head,current)
- if t then
- if free_too then
- free_node(t)
- t=nil
- else
- t.next,t.prev=nil,nil
- end
- end
- return head,current,t
-end -function nodes.delete(head,current)
- return nodes.remove(head,current,true)
-end -nodes.before=node.insert_before
+function nodes.remove(head,current,free_too) + local t=current + head,current=remove_node(head,current) + if t then + if free_too then + free_node(t) + t=nil + else + t.next,t.prev=nil,nil + end + end + return head,current,t +end +function nodes.delete(head,current) + return nodes.remove(head,current,true) +end +nodes.before=node.insert_before nodes.after=node.insert_after -function nodes.pool.kern(k)
- local n=new_node("kern",1)
- n.kern=k
- return n
-end -function nodes.endofmath(n)
- for n in traverse_id(math_code,n.next) do
- return n
- end
-end
+function nodes.pool.kern(k) + local n=new_node("kern",1) + n.kern=k + return n +end +function nodes.endofmath(n) + for n in traverse_id(math_code,n.next) do + return n + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-ini']={
- 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"
+if not modules then modules={} end modules ['font-ini']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local report_defining=logs.reporter("fonts","defining") -fonts=fonts or {}
+fonts=fonts or {} local fonts=fonts fonts.hashes={ identifiers=allocate() } -fonts.tables=fonts.tables or {}
-fonts.helpers=fonts.helpers or {}
+fonts.tables=fonts.tables or {} +fonts.helpers=fonts.helpers or {} fonts.tracers=fonts.tracers or {} fonts.specifiers=fonts.specifiers or {} fonts.analyzers={} -fonts.readers={}
-fonts.definers={ methods={} }
+fonts.readers={} +fonts.definers={ methods={} } fonts.loggers={ register=function() end } -fontloader.totable=fontloader.to_table
+fontloader.totable=fontloader.to_table end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-con']={
- 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"
+if not modules then modules={} end modules ['font-con']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local next,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 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 -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
+local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end) local report_defining=logs.reporter("fonts","defining") -local fonts=fonts
-local constructors=fonts.constructors or {}
-fonts.constructors=constructors
+local fonts=fonts +local constructors=fonts.constructors or {} +fonts.constructors=constructors local handlers=fonts.handlers or {} fonts.handlers=handlers -local allocate=utilities.storage.allocate
+local allocate=utilities.storage.allocate local setmetatableindex=table.setmetatableindex -constructors.dontembed=allocate()
-constructors.autocleanup=true
+constructors.dontembed=allocate() +constructors.autocleanup=true constructors.namemode="fullpath" -constructors.version=1.01
+constructors.version=1.01 constructors.cache=containers.define("fonts","constructors",constructors.version,false) constructors.privateoffset=0xF0000 -constructors.keys={
- properties={
- encodingbytes="number",
- embedding="number",
- cidinfo={},
- format="string",
- fontname="string",
- fullname="string",
- filename="filename",
- psname="string",
- name="string",
- virtualized="boolean",
- hasitalics="boolean",
- autoitalicamount="basepoints",
- nostackmath="boolean",
- noglyphnames="boolean",
- mode="string",
- hasmath="boolean",
- mathitalics="boolean",
- textitalics="boolean",
- finalized="boolean",
- },
- parameters={
- mathsize="number",
- scriptpercentage="float",
- scriptscriptpercentage="float",
- units="cardinal",
- designsize="scaledpoints",
- expansion={
+constructors.keys={ + properties={ + encodingbytes="number", + embedding="number", + cidinfo={}, + format="string", + fontname="string", + fullname="string", + filename="filename", + psname="string", + name="string", + virtualized="boolean", + hasitalics="boolean", + autoitalicamount="basepoints", + nostackmath="boolean", + noglyphnames="boolean", + mode="string", + hasmath="boolean", + mathitalics="boolean", + textitalics="boolean", + finalized="boolean", + }, + parameters={ + mathsize="number", + scriptpercentage="float", + scriptscriptpercentage="float", + units="cardinal", + designsize="scaledpoints", + expansion={ stretch="integerscale", shrink="integerscale", step="integerscale", - auto="boolean",
- },
- protrusion={
- auto="boolean",
- },
- slantfactor="float",
- extendfactor="float",
- factor="float",
- hfactor="float",
- vfactor="float",
- size="scaledpoints",
- units="scaledpoints",
- scaledpoints="scaledpoints",
- slantperpoint="scaledpoints",
- spacing={
- width="scaledpoints",
- stretch="scaledpoints",
- shrink="scaledpoints",
- extra="scaledpoints",
- },
- xheight="scaledpoints",
- quad="scaledpoints",
- ascender="scaledpoints",
- descender="scaledpoints",
- synonyms={
- space="spacing.width",
- spacestretch="spacing.stretch",
- spaceshrink="spacing.shrink",
- extraspace="spacing.extra",
- x_height="xheight",
- space_stretch="spacing.stretch",
- space_shrink="spacing.shrink",
- extra_space="spacing.extra",
- em="quad",
- ex="xheight",
- slant="slantperpoint",
- },
- },
- description={
- width="basepoints",
- height="basepoints",
- depth="basepoints",
- boundingbox={},
- },
- character={
- width="scaledpoints",
- height="scaledpoints",
- depth="scaledpoints",
- italic="scaledpoints",
- },
+ auto="boolean", + }, + protrusion={ + auto="boolean", + }, + slantfactor="float", + extendfactor="float", + factor="float", + hfactor="float", + vfactor="float", + size="scaledpoints", + units="scaledpoints", + scaledpoints="scaledpoints", + slantperpoint="scaledpoints", + spacing={ + width="scaledpoints", + stretch="scaledpoints", + shrink="scaledpoints", + extra="scaledpoints", + }, + xheight="scaledpoints", + quad="scaledpoints", + ascender="scaledpoints", + descender="scaledpoints", + synonyms={ + space="spacing.width", + spacestretch="spacing.stretch", + spaceshrink="spacing.shrink", + extraspace="spacing.extra", + x_height="xheight", + space_stretch="spacing.stretch", + space_shrink="spacing.shrink", + extra_space="spacing.extra", + em="quad", + ex="xheight", + slant="slantperpoint", + }, + }, + description={ + width="basepoints", + height="basepoints", + depth="basepoints", + boundingbox={}, + }, + character={ + width="scaledpoints", + height="scaledpoints", + depth="scaledpoints", + italic="scaledpoints", + }, } -local designsizes=allocate()
-constructors.designsizes=designsizes
-local loadedfonts=allocate()
+local designsizes=allocate() +constructors.designsizes=designsizes +local loadedfonts=allocate() constructors.loadedfonts=loadedfonts -local factors={
- pt=65536.0,
- bp=65781.8,
+local factors={ + pt=65536.0, + bp=65781.8, } -function constructors.setfactor(f)
- constructors.factor=factors[f or 'pt'] or factors.pt
+function constructors.setfactor(f) + constructors.factor=factors[f or 'pt'] or factors.pt end constructors.setfactor() function constructors.scaled(scaledpoints,designsize) - if scaledpoints<0 then
- if designsize then
- local factor=constructors.factor
+ if scaledpoints<0 then + if designsize then + local factor=constructors.factor if designsize>factor then return (- scaledpoints/1000)*designsize - else
- return (- scaledpoints/1000)*designsize*factor
- end
- else
- return (- scaledpoints/1000)*10*factor
- end
- else
- return scaledpoints
- end
-end -function constructors.cleanuptable(tfmdata)
- if constructors.autocleanup and tfmdata.properties.virtualized then
- for k,v in next,tfmdata.characters do
+ else + return (- scaledpoints/1000)*designsize*factor + end + else + return (- scaledpoints/1000)*10*factor + end + else + return scaledpoints + end +end +function constructors.cleanuptable(tfmdata) + if constructors.autocleanup and tfmdata.properties.virtualized then + for k,v in next,tfmdata.characters do if v.commands then v.commands=nil end - end
- end
+ end + end end -function constructors.calculatescale(tfmdata,scaledpoints)
- local parameters=tfmdata.parameters
- if scaledpoints<0 then
+function constructors.calculatescale(tfmdata,scaledpoints) + local parameters=tfmdata.parameters + if scaledpoints<0 then scaledpoints=(- scaledpoints/1000)*(tfmdata.designsize or parameters.designsize) - end
+ end return scaledpoints,scaledpoints/(parameters.units or 1000) end -local unscaled={
- ScriptPercentScaleDown=true,
- ScriptScriptPercentScaleDown=true,
- RadicalDegreeBottomRaisePercent=true
+local unscaled={ + ScriptPercentScaleDown=true, + ScriptScriptPercentScaleDown=true, + RadicalDegreeBottomRaisePercent=true } function constructors.assignmathparameters(target,original) - local mathparameters=original.mathparameters
- if mathparameters and next(mathparameters) then
- local targetparameters=target.parameters
- local targetproperties=target.properties
- local targetmathparameters={}
- local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor
- for name,value in next,mathparameters do
- if unscaled[name] then
- targetmathparameters[name]=value
- else
- targetmathparameters[name]=value*factor
- end
- end
- if not targetmathparameters.FractionDelimiterSize then
- targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size
- end
- if not mathparameters.FractionDelimiterDisplayStyleSize then
- targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size
- end
- target.mathparameters=targetmathparameters
- end
+ local mathparameters=original.mathparameters + if mathparameters and next(mathparameters) then + local targetparameters=target.parameters + local targetproperties=target.properties + local targetmathparameters={} + local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor + for name,value in next,mathparameters do + if unscaled[name] then + targetmathparameters[name]=value + else + targetmathparameters[name]=value*factor + end + end + if not targetmathparameters.FractionDelimiterSize then + targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size + end + if not mathparameters.FractionDelimiterDisplayStyleSize then + targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size + end + target.mathparameters=targetmathparameters + end end function constructors.beforecopyingcharacters(target,original) end function constructors.aftercopyingcharacters(target,original) end -function constructors.enhanceparameters(parameters)
- local xheight=parameters.x_height
- local quad=parameters.quad
- local space=parameters.space
- local stretch=parameters.space_stretch
- local shrink=parameters.space_shrink
- local extra=parameters.extra_space
- local slant=parameters.slant
- parameters.xheight=xheight
- parameters.spacestretch=stretch
- parameters.spaceshrink=shrink
- parameters.extraspace=extra
- parameters.em=quad
- parameters.ex=xheight
- parameters.slantperpoint=slant
- parameters.spacing={
- width=space,
- stretch=stretch,
- shrink=shrink,
- extra=extra,
- }
-end -function constructors.scale(tfmdata,specification)
+function constructors.enhanceparameters(parameters) + local xheight=parameters.x_height + local quad=parameters.quad + local space=parameters.space + local stretch=parameters.space_stretch + local shrink=parameters.space_shrink + local extra=parameters.extra_space + local slant=parameters.slant + parameters.xheight=xheight + parameters.spacestretch=stretch + parameters.spaceshrink=shrink + parameters.extraspace=extra + parameters.em=quad + parameters.ex=xheight + parameters.slantperpoint=slant + parameters.spacing={ + width=space, + stretch=stretch, + shrink=shrink, + extra=extra, + } +end +function constructors.scale(tfmdata,specification) local target={} - if tonumber(specification) then
- specification={ size=specification }
+ if tonumber(specification) then + specification={ size=specification } end - local scaledpoints=specification.size
+ local scaledpoints=specification.size local relativeid=specification.relativeid - local properties=tfmdata.properties or {}
- local goodies=tfmdata.goodies or {}
- local resources=tfmdata.resources or {}
+ local properties=tfmdata.properties or {} + local goodies=tfmdata.goodies or {} + local resources=tfmdata.resources or {} local descriptions=tfmdata.descriptions or {} local characters=tfmdata.characters or {} local changed=tfmdata.changed or {} - local shared=tfmdata.shared or {}
- local parameters=tfmdata.parameters or {}
+ local shared=tfmdata.shared or {} + local parameters=tfmdata.parameters or {} local mathparameters=tfmdata.mathparameters or {} - local targetcharacters={}
- local targetdescriptions=derivetable(descriptions)
- local targetparameters=derivetable(parameters)
- local targetproperties=derivetable(properties)
+ local targetcharacters={} + local targetdescriptions=derivetable(descriptions) + local targetparameters=derivetable(parameters) + local targetproperties=derivetable(properties) local targetgoodies=goodies - target.characters=targetcharacters
- target.descriptions=targetdescriptions
+ target.characters=targetcharacters + target.descriptions=targetdescriptions target.parameters=targetparameters - target.properties=targetproperties
- target.goodies=targetgoodies
- target.shared=shared
- target.resources=resources
+ target.properties=targetproperties + target.goodies=targetgoodies + target.shared=shared + target.resources=resources target.unscaled=tfmdata - local mathsize=tonumber(specification.mathsize) or 0
- local textsize=tonumber(specification.textsize) or scaledpoints
- local forcedsize=tonumber(parameters.mathsize ) or 0
- local extrafactor=tonumber(specification.factor ) or 1
- if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then
- scaledpoints=parameters.scriptpercentage*textsize/100
- elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then
- scaledpoints=parameters.scriptscriptpercentage*textsize/100
+ local mathsize=tonumber(specification.mathsize) or 0 + local textsize=tonumber(specification.textsize) or scaledpoints + local forcedsize=tonumber(parameters.mathsize ) or 0 + local extrafactor=tonumber(specification.factor ) or 1 + if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then + scaledpoints=parameters.scriptpercentage*textsize/100 + elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then + scaledpoints=parameters.scriptscriptpercentage*textsize/100 elseif forcedsize>1000 then - scaledpoints=forcedsize
- end
+ scaledpoints=forcedsize + end targetparameters.mathsize=mathsize targetparameters.textsize=textsize targetparameters.forcedsize=forcedsize targetparameters.extrafactor=extrafactor - local tounicode=resources.tounicode
- local defaultwidth=resources.defaultwidth or 0
- local defaultheight=resources.defaultheight or 0
- local defaultdepth=resources.defaultdepth or 0
+ local tounicode=resources.tounicode + local defaultwidth=resources.defaultwidth or 0 + local defaultheight=resources.defaultheight or 0 + local defaultdepth=resources.defaultdepth or 0 local units=parameters.units or 1000 - if target.fonts then
+ if target.fonts then target.fonts=fastcopy(target.fonts) end targetproperties.language=properties.language or "dflt" targetproperties.script=properties.script or "dflt" targetproperties.mode=properties.mode or "base" - local askedscaledpoints=scaledpoints
+ local askedscaledpoints=scaledpoints local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints) - local hdelta=delta
+ local hdelta=delta local vdelta=delta target.designsize=parameters.designsize target.units_per_em=units local direction=properties.direction or tfmdata.direction or 0 - target.direction=direction
+ target.direction=direction properties.direction=direction target.size=scaledpoints - target.encodingbytes=properties.encodingbytes or 1
- target.embedding=properties.embedding or "subset"
- target.tounicode=1
- target.cidinfo=properties.cidinfo
+ target.encodingbytes=properties.encodingbytes or 1 + target.embedding=properties.embedding or "subset" + target.tounicode=1 + target.cidinfo=properties.cidinfo target.format=properties.format local fontname=properties.fontname or tfmdata.fontname local fullname=properties.fullname or tfmdata.fullname @@ -3645,4275 +3645,4275 @@ function constructors.scale(tfmdata,specification) local psname=properties.psname or tfmdata.psname local name=properties.name or tfmdata.name if not psname or psname=="" then - psname=fontname or (fullname and fonts.names.cleanname(fullname))
- end
- target.fontname=fontname
- target.fullname=fullname
- target.filename=filename
- target.psname=psname
+ psname=fontname or (fullname and fonts.names.cleanname(fullname)) + end + target.fontname=fontname + target.fullname=fullname + target.filename=filename + target.psname=psname target.name=name - properties.fontname=fontname
- properties.fullname=fullname
- properties.filename=filename
- properties.psname=psname
+ properties.fontname=fontname + properties.fullname=fullname + properties.filename=filename + properties.psname=psname properties.name=name - local expansion=parameters.expansion
- if expansion then
- target.stretch=expansion.stretch
- target.shrink=expansion.shrink
- target.step=expansion.step
- target.auto_expand=expansion.auto
- end - local protrusion=parameters.protrusion
- if protrusion then
- target.auto_protrude=protrusion.auto
- end - local extendfactor=parameters.extendfactor or 0
- if extendfactor~=0 and extendfactor~=1 then
- hdelta=hdelta*extendfactor
+ local expansion=parameters.expansion + if expansion then + target.stretch=expansion.stretch + target.shrink=expansion.shrink + target.step=expansion.step + target.auto_expand=expansion.auto + end + local protrusion=parameters.protrusion + if protrusion then + target.auto_protrude=protrusion.auto + end + local extendfactor=parameters.extendfactor or 0 + if extendfactor~=0 and extendfactor~=1 then + hdelta=hdelta*extendfactor target.extend=extendfactor*1000 - else
+ else target.extend=1000 end - local slantfactor=parameters.slantfactor or 0
- if slantfactor~=0 then
- target.slant=slantfactor*1000
- else
- target.slant=0
- end - targetparameters.factor=delta
- targetparameters.hfactor=hdelta
- targetparameters.vfactor=vdelta
- targetparameters.size=scaledpoints
- targetparameters.units=units
+ local slantfactor=parameters.slantfactor or 0 + if slantfactor~=0 then + target.slant=slantfactor*1000 + else + target.slant=0 + end + targetparameters.factor=delta + targetparameters.hfactor=hdelta + targetparameters.vfactor=vdelta + targetparameters.size=scaledpoints + targetparameters.units=units targetparameters.scaledpoints=askedscaledpoints - local isvirtual=properties.virtualized or tfmdata.type=="virtual"
- local hasquality=target.auto_expand or target.auto_protrude
- local hasitalics=properties.hasitalics
- local autoitalicamount=properties.autoitalicamount
- local stackmath=not properties.nostackmath
- local nonames=properties.noglyphnames
+ local isvirtual=properties.virtualized or tfmdata.type=="virtual" + local hasquality=target.auto_expand or target.auto_protrude + local hasitalics=properties.hasitalics + local autoitalicamount=properties.autoitalicamount + local stackmath=not properties.nostackmath + local nonames=properties.noglyphnames local nodemode=properties.mode=="node" - if changed and not next(changed) then
- changed=false
+ if changed and not next(changed) then + changed=false end target.type=isvirtual and "virtual" or "real" target.postprocessors=tfmdata.postprocessors - local targetslant=(parameters.slant or parameters[1] or 0)
- local targetspace=(parameters.space or parameters[2] or 0)*hdelta
- local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta
- local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta
- local targetx_height=(parameters.x_height or parameters[5] or 0)*vdelta
- local targetquad=(parameters.quad or parameters[6] or 0)*hdelta
+ local targetslant=(parameters.slant or parameters[1] or 0) + local targetspace=(parameters.space or parameters[2] or 0)*hdelta + local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta + local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta + local targetx_height=(parameters.x_height or parameters[5] or 0)*vdelta + local targetquad=(parameters.quad or parameters[6] or 0)*hdelta local targetextra_space=(parameters.extra_space or parameters[7] or 0)*hdelta targetparameters.slant=targetslant - targetparameters.space=targetspace
- targetparameters.space_stretch=targetspace_stretch
- targetparameters.space_shrink=targetspace_shrink
- targetparameters.x_height=targetx_height
- targetparameters.quad=targetquad
+ targetparameters.space=targetspace + targetparameters.space_stretch=targetspace_stretch + targetparameters.space_shrink=targetspace_shrink + targetparameters.x_height=targetx_height + targetparameters.quad=targetquad targetparameters.extra_space=targetextra_space - local ascender=parameters.ascender
- if ascender then
- targetparameters.ascender=delta*ascender
- end
- local descender=parameters.descender
- if descender then
- targetparameters.descender=delta*descender
+ local ascender=parameters.ascender + if ascender then + targetparameters.ascender=delta*ascender + end + local descender=parameters.descender + if descender then + targetparameters.descender=delta*descender end constructors.enhanceparameters(targetparameters) - local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0
- local scaledwidth=defaultwidth*hdelta
- local scaledheight=defaultheight*vdelta
+ local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0 + local scaledwidth=defaultwidth*hdelta + local scaledheight=defaultheight*vdelta local scaleddepth=defaultdepth*vdelta local hasmath=(properties.hasmath or next(mathparameters)) and true - if hasmath then
+ if hasmath then constructors.assignmathparameters(target,tfmdata) - properties.hasmath=true
- target.nomath=false
- target.MathConstants=target.mathparameters
- else
- properties.hasmath=false
- target.nomath=true
+ properties.hasmath=true + target.nomath=false + target.MathConstants=target.mathparameters + else + properties.hasmath=false + target.nomath=true target.mathparameters=nil end - local italickey="italic"
+ local italickey="italic" local useitalics=true if hasmath then autoitalicamount=false - elseif properties.textitalics then
- italickey="italic_correction"
- useitalics=false
- if properties.delaytextitalics then
- autoitalicamount=false
- end
- end - if trace_defining then
- report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a",
- name,fullname,filename,hdelta,vdelta,
- hasmath and "enabled" or "disabled",useitalics and "enabled" or "disabled")
+ elseif properties.textitalics then + italickey="italic_correction" + useitalics=false + if properties.delaytextitalics then + autoitalicamount=false + end + end + if trace_defining then + report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a", + name,fullname,filename,hdelta,vdelta, + hasmath and "enabled" or "disabled",useitalics and "enabled" or "disabled") end constructors.beforecopyingcharacters(target,tfmdata) local sharedkerns={} - for unicode,character in next,characters do
- local chr,description,index,touni
+ for unicode,character in next,characters do + local chr,description,index,touni if changed then - local c=changed[unicode]
- if c then
- description=descriptions[c] or descriptions[unicode] or character
- character=characters[c] or character
- index=description.index or c
- if tounicode then
+ local c=changed[unicode] + if c then + description=descriptions[c] or descriptions[unicode] or character + character=characters[c] or character + index=description.index or c + if tounicode then touni=tounicode[index] if not touni then - local d=descriptions[unicode] or characters[unicode]
- local i=d.index or unicode
+ local d=descriptions[unicode] or characters[unicode] + local i=d.index or unicode touni=tounicode[i] - end
- end
- else
- description=descriptions[unicode] or character
- index=description.index or unicode
- if tounicode then
+ end + end + else + description=descriptions[unicode] or character + index=description.index or unicode + if tounicode then touni=tounicode[index] - end
- end
- else
- description=descriptions[unicode] or character
- index=description.index or unicode
- if tounicode then
+ end + end + else + description=descriptions[unicode] or character + index=description.index or unicode + if tounicode then touni=tounicode[index] - end
- end
- local width=description.width
- local height=description.height
- local depth=description.depth
- if width then width=hdelta*width else width=scaledwidth end
+ end + end + local width=description.width + local height=description.height + local depth=description.depth + if width then width=hdelta*width else width=scaledwidth end if height then height=vdelta*height else height=scaledheight end - if depth and depth~=0 then
- depth=delta*depth
- if nonames then
- chr={
- index=index,
- height=height,
- depth=depth,
- width=width,
- }
- else
- chr={
- name=description.name,
- index=index,
- height=height,
- depth=depth,
- width=width,
- }
- end
+ if depth and depth~=0 then + depth=delta*depth + if nonames then + chr={ + index=index, + height=height, + depth=depth, + width=width, + } + else + chr={ + name=description.name, + index=index, + height=height, + depth=depth, + width=width, + } + end else - if nonames then
- chr={
- index=index,
- height=height,
- width=width,
- }
- else
- chr={
- name=description.name,
- index=index,
- height=height,
- width=width,
- }
- end
- end
- if touni then
- chr.tounicode=touni
- end
+ if nonames then + chr={ + index=index, + height=height, + width=width, + } + else + chr={ + name=description.name, + index=index, + height=height, + width=width, + } + end + end + if touni then + chr.tounicode=touni + end if hasquality then - local ve=character.expansion_factor
- if ve then
+ local ve=character.expansion_factor + if ve then chr.expansion_factor=ve*1000 - end
- local vl=character.left_protruding
- if vl then
- chr.left_protruding=protrusionfactor*width*vl
- end
- local vr=character.right_protruding
- if vr then
- chr.right_protruding=protrusionfactor*width*vr
- end
- end - if autoitalicamount then
- local vi=description.italic
- if not vi then
- local vi=description.boundingbox[3]-description.width+autoitalicamount
+ end + local vl=character.left_protruding + if vl then + chr.left_protruding=protrusionfactor*width*vl + end + local vr=character.right_protruding + if vr then + chr.right_protruding=protrusionfactor*width*vr + end + end + if autoitalicamount then + local vi=description.italic + if not vi then + local vi=description.boundingbox[3]-description.width+autoitalicamount if vi>0 then - chr[italickey]=vi*hdelta
- end
- elseif vi~=0 then
- chr[italickey]=vi*hdelta
- end
- elseif hasitalics then
- local vi=description.italic
- if vi and vi~=0 then
- chr[italickey]=vi*hdelta
- end
+ chr[italickey]=vi*hdelta + end + elseif vi~=0 then + chr[italickey]=vi*hdelta + end + elseif hasitalics then + local vi=description.italic + if vi and vi~=0 then + chr[italickey]=vi*hdelta + end end if hasmath then - local vn=character.next
- if vn then
- chr.next=vn
- else
- local vv=character.vert_variants
- if vv then
- local t={}
- for i=1,#vv do
- local vvi=vv[i]
- t[i]={
- ["start"]=(vvi["start"] or 0)*vdelta,
- ["end"]=(vvi["end"] or 0)*vdelta,
- ["advance"]=(vvi["advance"] or 0)*vdelta,
- ["extender"]=vvi["extender"],
- ["glyph"]=vvi["glyph"],
- }
- end
- chr.vert_variants=t
- else
- local hv=character.horiz_variants
- if hv then
- local t={}
- for i=1,#hv do
- local hvi=hv[i]
- t[i]={
- ["start"]=(hvi["start"] or 0)*hdelta,
- ["end"]=(hvi["end"] or 0)*hdelta,
- ["advance"]=(hvi["advance"] or 0)*hdelta,
- ["extender"]=hvi["extender"],
- ["glyph"]=hvi["glyph"],
- }
- end
- chr.horiz_variants=t
- end
- end
- end
- local va=character.top_accent
- if va then
- chr.top_accent=vdelta*va
- end
- if stackmath then
+ local vn=character.next + if vn then + chr.next=vn + else + local vv=character.vert_variants + if vv then + local t={} + for i=1,#vv do + local vvi=vv[i] + t[i]={ + ["start"]=(vvi["start"] or 0)*vdelta, + ["end"]=(vvi["end"] or 0)*vdelta, + ["advance"]=(vvi["advance"] or 0)*vdelta, + ["extender"]=vvi["extender"], + ["glyph"]=vvi["glyph"], + } + end + chr.vert_variants=t + else + local hv=character.horiz_variants + if hv then + local t={} + for i=1,#hv do + local hvi=hv[i] + t[i]={ + ["start"]=(hvi["start"] or 0)*hdelta, + ["end"]=(hvi["end"] or 0)*hdelta, + ["advance"]=(hvi["advance"] or 0)*hdelta, + ["extender"]=hvi["extender"], + ["glyph"]=hvi["glyph"], + } + end + chr.horiz_variants=t + end + end + end + local va=character.top_accent + if va then + chr.top_accent=vdelta*va + end + if stackmath then 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
+ 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 - end
- end
- end
- if not nodemode then
- local vk=character.kerns
- if vk then
- local s=sharedkerns[vk]
- if not s then
- s={}
- for k,v in next,vk do s[k]=v*hdelta end
- sharedkerns[vk]=s
- end
- chr.kerns=s
- end
- local vl=character.ligatures
- if vl then
- if true then
+ end + end + end + if not nodemode then + local vk=character.kerns + if vk then + local s=sharedkerns[vk] + if not s then + s={} + for k,v in next,vk do s[k]=v*hdelta end + sharedkerns[vk]=s + end + chr.kerns=s + end + local vl=character.ligatures + if vl then + if true then chr.ligatures=vl - else
- local tt={}
- for i,l in next,vl do
- tt[i]=l
- end
- chr.ligatures=tt
- end
- end
- end
- if isvirtual then
- local vc=character.commands
+ else + local tt={} + for i,l in next,vl do + tt[i]=l + end + chr.ligatures=tt + end + end + end + if isvirtual then + local vc=character.commands if vc then - local ok=false
- for i=1,#vc do
- local key=vc[i][1]
- if key=="right" or key=="down" then
- ok=true
- break
- end
- end
- if ok then
- local tt={}
- for i=1,#vc do
- local ivc=vc[i]
- local key=ivc[1]
- if key=="right" then
- tt[i]={ key,ivc[2]*hdelta }
- elseif key=="down" then
- tt[i]={ key,ivc[2]*vdelta }
- elseif key=="rule" then
- tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta }
+ local ok=false + for i=1,#vc do + local key=vc[i][1] + if key=="right" or key=="down" then + ok=true + break + end + end + if ok then + local tt={} + for i=1,#vc do + local ivc=vc[i] + local key=ivc[1] + if key=="right" then + tt[i]={ key,ivc[2]*hdelta } + elseif key=="down" then + tt[i]={ key,ivc[2]*vdelta } + elseif key=="rule" then + tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta } else tt[i]=ivc - end
- end
- chr.commands=tt
- else
- chr.commands=vc
- end
- chr.index=nil
- end
- end
- targetcharacters[unicode]=chr
+ end + end + chr.commands=tt + else + chr.commands=vc + end + chr.index=nil + end + end + targetcharacters[unicode]=chr end constructors.aftercopyingcharacters(target,tfmdata) - return target
+ return target end -function constructors.finalize(tfmdata)
- if tfmdata.properties and tfmdata.properties.finalized then
- return
+function constructors.finalize(tfmdata) + if tfmdata.properties and tfmdata.properties.finalized then + return end - if not tfmdata.characters then
- return nil
+ if not tfmdata.characters then + return nil end - if not tfmdata.goodies then
+ if not tfmdata.goodies then tfmdata.goodies={} end - local parameters=tfmdata.parameters
- if not parameters then
- return nil
+ local parameters=tfmdata.parameters + if not parameters then + return nil end - if not parameters.expansion then
- parameters.expansion={
- stretch=tfmdata.stretch or 0,
- shrink=tfmdata.shrink or 0,
- step=tfmdata.step or 0,
- auto=tfmdata.auto_expand or false,
- }
+ if not parameters.expansion then + parameters.expansion={ + stretch=tfmdata.stretch or 0, + shrink=tfmdata.shrink or 0, + step=tfmdata.step or 0, + auto=tfmdata.auto_expand or false, + } end - if not parameters.protrusion then
- parameters.protrusion={
- auto=auto_protrude
- }
+ if not parameters.protrusion then + parameters.protrusion={ + auto=auto_protrude + } end - if not parameters.size then
- parameters.size=tfmdata.size
+ if not parameters.size then + parameters.size=tfmdata.size end - if not parameters.extendfactor then
- parameters.extendfactor=tfmdata.extend or 0
+ if not parameters.extendfactor then + parameters.extendfactor=tfmdata.extend or 0 end - if not parameters.slantfactor then
- parameters.slantfactor=tfmdata.slant or 0
+ if not parameters.slantfactor then + parameters.slantfactor=tfmdata.slant or 0 end - if not parameters.designsize then
- parameters.designsize=tfmdata.designsize or 655360
+ if not parameters.designsize then + parameters.designsize=tfmdata.designsize or 655360 end - if not parameters.units then
- parameters.units=tfmdata.units_per_em or 1000
+ if not parameters.units then + parameters.units=tfmdata.units_per_em or 1000 end - if not tfmdata.descriptions then
+ if not tfmdata.descriptions then local descriptions={} - setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end)
- tfmdata.descriptions=descriptions
- end - local properties=tfmdata.properties
- if not properties then
- properties={}
- tfmdata.properties=properties
- end - if not properties.virtualized then
- properties.virtualized=tfmdata.type=="virtual"
- end - if not tfmdata.properties then
- tfmdata.properties={
- fontname=tfmdata.fontname,
- filename=tfmdata.filename,
- fullname=tfmdata.fullname,
- name=tfmdata.name,
+ setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end) + tfmdata.descriptions=descriptions + end + local properties=tfmdata.properties + if not properties then + properties={} + tfmdata.properties=properties + end + if not properties.virtualized then + properties.virtualized=tfmdata.type=="virtual" + end + if not tfmdata.properties then + tfmdata.properties={ + fontname=tfmdata.fontname, + filename=tfmdata.filename, + fullname=tfmdata.fullname, + name=tfmdata.name, psname=tfmdata.psname, - encodingbytes=tfmdata.encodingbytes or 1,
- embedding=tfmdata.embedding or "subset",
- tounicode=tfmdata.tounicode or 1,
- cidinfo=tfmdata.cidinfo or nil,
- format=tfmdata.format or "type1",
- direction=tfmdata.direction or 0,
- }
- end
- if not tfmdata.resources then
- tfmdata.resources={}
- end
- if not tfmdata.shared then
- tfmdata.shared={}
- end - if not properties.hasmath then
- properties.hasmath=not tfmdata.nomath
- end - tfmdata.MathConstants=nil
+ encodingbytes=tfmdata.encodingbytes or 1, + embedding=tfmdata.embedding or "subset", + tounicode=tfmdata.tounicode or 1, + cidinfo=tfmdata.cidinfo or nil, + format=tfmdata.format or "type1", + direction=tfmdata.direction or 0, + } + end + if not tfmdata.resources then + tfmdata.resources={} + end + if not tfmdata.shared then + tfmdata.shared={} + end + if not properties.hasmath then + properties.hasmath=not tfmdata.nomath + end + tfmdata.MathConstants=nil tfmdata.postprocessors=nil - tfmdata.fontname=nil
- tfmdata.filename=nil
- tfmdata.fullname=nil
+ tfmdata.fontname=nil + tfmdata.filename=nil + tfmdata.fullname=nil tfmdata.name=nil tfmdata.psname=nil - tfmdata.encodingbytes=nil
- tfmdata.embedding=nil
- tfmdata.tounicode=nil
- tfmdata.cidinfo=nil
- tfmdata.format=nil
- tfmdata.direction=nil
- tfmdata.type=nil
- tfmdata.nomath=nil
+ tfmdata.encodingbytes=nil + tfmdata.embedding=nil + tfmdata.tounicode=nil + tfmdata.cidinfo=nil + tfmdata.format=nil + tfmdata.direction=nil + tfmdata.type=nil + tfmdata.nomath=nil tfmdata.designsize=nil - tfmdata.size=nil
- tfmdata.stretch=nil
- tfmdata.shrink=nil
- tfmdata.step=nil
- tfmdata.auto_expand=nil
- tfmdata.auto_protrude=nil
- tfmdata.extend=nil
- tfmdata.slant=nil
+ tfmdata.size=nil + tfmdata.stretch=nil + tfmdata.shrink=nil + tfmdata.step=nil + tfmdata.auto_expand=nil + tfmdata.auto_protrude=nil + tfmdata.extend=nil + tfmdata.slant=nil tfmdata.units_per_em=nil properties.finalized=true - return tfmdata
+ return tfmdata end -local hashmethods={}
+local hashmethods={} constructors.hashmethods=hashmethods function constructors.hashfeatures(specification) - local features=specification.features
- if features then
- local t,tn={},0
- for category,list in next,features do
- if next(list) then
- local hasher=hashmethods[category]
- if hasher then
- local hash=hasher(list)
- if hash then
- tn=tn+1
- t[tn]=category..":"..hash
- end
- end
- end
- end
- if tn>0 then
- return concat(t," & ")
- end
- end
- return "unknown"
-end -hashmethods.normal=function(list)
- local s={}
- local n=0
- for k,v in next,list do
+ local features=specification.features + if features then + local t,tn={},0 + for category,list in next,features do + if next(list) then + local hasher=hashmethods[category] + if hasher then + local hash=hasher(list) + if hash then + tn=tn+1 + t[tn]=category..":"..hash + end + end + end + end + if tn>0 then + return concat(t," & ") + end + end + return "unknown" +end +hashmethods.normal=function(list) + local s={} + local n=0 + for k,v in next,list do if not k then elseif k=="number" or k=="features" then - 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 -function constructors.hashinstance(specification,force)
- local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks
- if force or not hash then
- hash=constructors.hashfeatures(specification)
- specification.hash=hash
- end
- if size<1000 and designsizes[hash] then
- size=math.round(constructors.scaled(size,designsizes[hash]))
- specification.size=size
- end - if fallbacks then
- return hash..' @ '..tostring(size)..' @ '..fallbacks
- else
- return hash..' @ '..tostring(size)
+ 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 +function constructors.hashinstance(specification,force) + local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks + if force or not hash then + hash=constructors.hashfeatures(specification) + specification.hash=hash + end + if size<1000 and designsizes[hash] then + size=math.round(constructors.scaled(size,designsizes[hash])) + specification.size=size + end + if fallbacks then + return hash..' @ '..tostring(size)..' @ '..fallbacks + else + return hash..' @ '..tostring(size) end end function constructors.setname(tfmdata,specification) if constructors.namemode=="specification" then - local specname=specification.specification
- if specname then
- tfmdata.properties.name=specname
- if trace_defining then
- report_otf("overloaded fontname %a",specname)
- end
- end
- end
-end -function constructors.checkedfilename(data)
- local foundfilename=data.foundfilename
- if not foundfilename then
- local askedfilename=data.filename or ""
- if askedfilename~="" then
+ local specname=specification.specification + if specname then + tfmdata.properties.name=specname + if trace_defining then + report_otf("overloaded fontname %a",specname) + end + end + end +end +function constructors.checkedfilename(data) + local foundfilename=data.foundfilename + if not foundfilename then + local askedfilename=data.filename or "" + if askedfilename~="" then askedfilename=resolvers.resolve(askedfilename) - foundfilename=resolvers.findbinfile(askedfilename,"") or ""
- if foundfilename=="" then
- report_defining("source file %a is not found",askedfilename)
- foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or ""
- if foundfilename~="" then
- report_defining("using source file %a due to cache mismatch",foundfilename)
- end
- end
- end
- data.foundfilename=foundfilename
- end
- return foundfilename
-end -local formats=allocate()
+ foundfilename=resolvers.findbinfile(askedfilename,"") or "" + if foundfilename=="" then + report_defining("source file %a is not found",askedfilename) + foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or "" + if foundfilename~="" then + report_defining("using source file %a due to cache mismatch",foundfilename) + end + end + end + data.foundfilename=foundfilename + end + return foundfilename +end +local formats=allocate() fonts.formats=formats -setmetatableindex(formats,function(t,k)
- local l=lower(k)
- if rawget(t,k) then
- t[k]=l
- return l
- end
- return rawget(t,file.suffix(l))
+setmetatableindex(formats,function(t,k) + local l=lower(k) + if rawget(t,k) then + t[k]=l + return l + end + return rawget(t,file.suffix(l)) end) local locations={} -local function setindeed(mode,target,group,name,action,position)
- local t=target[mode]
- if not t then
- report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
- os.exit()
+local function setindeed(mode,target,group,name,action,position) + local t=target[mode] + if not t then + report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode) + os.exit() elseif position then - insert(t,position,{ name=name,action=action })
- else
- for i=1,#t do
- local ti=t[i]
- if ti.name==name then
- ti.action=action
- return
- end
- end
- insert(t,{ name=name,action=action })
- end
-end -local function set(group,name,target,source)
- target=target[group]
- if not target then
- report_defining("fatal target error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local source=source[group]
- if not source then
- report_defining("fatal source error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local node=source.node
- local base=source.base
- local position=source.position
- if node then
- setindeed("node",target,group,name,node,position)
- end
- if base then
- setindeed("base",target,group,name,base,position)
- end
-end -local function register(where,specification)
- local name=specification.name
- if name and name~="" then
- local default=specification.default
- local description=specification.description
- local initializers=specification.initializers
- local processors=specification.processors
- local manipulators=specification.manipulators
- local modechecker=specification.modechecker
- if default then
- where.defaults[name]=default
- end
- if description and description~="" then
- where.descriptions[name]=description
- end
- if initializers then
- set('initializers',name,where,specification)
- end
- if processors then
- set('processors',name,where,specification)
- end
- if manipulators then
- set('manipulators',name,where,specification)
- end
- if modechecker then
- where.modechecker=modechecker
- end
- end
+ insert(t,position,{ name=name,action=action }) + else + for i=1,#t do + local ti=t[i] + if ti.name==name then + ti.action=action + return + end + end + insert(t,{ name=name,action=action }) + end +end +local function set(group,name,target,source) + target=target[group] + if not target then + report_defining("fatal target error in setting feature %a, group %a",name,group) + os.exit() + end + local source=source[group] + if not source then + report_defining("fatal source error in setting feature %a, group %a",name,group) + os.exit() + end + local node=source.node + local base=source.base + local position=source.position + if node then + setindeed("node",target,group,name,node,position) + end + if base then + setindeed("base",target,group,name,base,position) + end +end +local function register(where,specification) + local name=specification.name + if name and name~="" then + local default=specification.default + local description=specification.description + local initializers=specification.initializers + local processors=specification.processors + local manipulators=specification.manipulators + local modechecker=specification.modechecker + if default then + where.defaults[name]=default + end + if description and description~="" then + where.descriptions[name]=description + end + if initializers then + set('initializers',name,where,specification) + end + if processors then + set('processors',name,where,specification) + end + if manipulators then + set('manipulators',name,where,specification) + end + if modechecker then + where.modechecker=modechecker + end + end end constructors.registerfeature=register -function constructors.getfeatureaction(what,where,mode,name)
- what=handlers[what].features
- if what then
- where=what[where]
- if where then
- mode=where[mode]
- if mode then
- for i=1,#mode do
- local m=mode[i]
- if m.name==name then
- return m.action
- end
- end
- end
- end
- end
+function constructors.getfeatureaction(what,where,mode,name) + what=handlers[what].features + if what then + where=what[where] + if where then + mode=where[mode] + if mode then + for i=1,#mode do + local m=mode[i] + if m.name==name then + return m.action + end + end + end + end + end end function constructors.newhandler(what) - local handler=handlers[what]
- if not handler then
- handler={}
- handlers[what]=handler
- end
- return handler
+ local handler=handlers[what] + if not handler then + handler={} + handlers[what]=handler + end + return handler end function constructors.newfeatures(what) - local handler=handlers[what]
- local features=handler.features
- if not features then
+ local handler=handlers[what] + local features=handler.features + if not features then local tables=handler.tables local statistics=handler.statistics - features=allocate {
- defaults={},
- descriptions=tables and tables.features or {},
- used=statistics and statistics.usedfeatures or {},
- initializers={ base={},node={} },
- processors={ base={},node={} },
- manipulators={ base={},node={} },
- }
- features.register=function(specification) return register(features,specification) end
+ features=allocate { + defaults={}, + descriptions=tables and tables.features or {}, + used=statistics and statistics.usedfeatures or {}, + initializers={ base={},node={} }, + processors={ base={},node={} }, + manipulators={ base={},node={} }, + } + features.register=function(specification) return register(features,specification) end handler.features=features - end
- return features
+ end + return features end -function constructors.checkedfeatures(what,features)
- local defaults=handlers[what].features.defaults
- if features and next(features) then
+function constructors.checkedfeatures(what,features) + local defaults=handlers[what].features.defaults + if features and next(features) then features=fastcopy(features) - for key,value in next,defaults do
- if features[key]==nil then
- features[key]=value
- end
- end
- return features
- else
+ for key,value in next,defaults do + if features[key]==nil then + features[key]=value + end + end + return features + else return fastcopy(defaults) - end
+ end end -function constructors.initializefeatures(what,tfmdata,features,trace,report)
- if features and next(features) then
+function constructors.initializefeatures(what,tfmdata,features,trace,report) + if features and next(features) then local properties=tfmdata.properties or {} - local whathandler=handlers[what]
- local whatfeatures=whathandler.features
- local whatinitializers=whatfeatures.initializers
+ local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatinitializers=whatfeatures.initializers local whatmodechecker=whatfeatures.modechecker - local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base"
+ local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base" properties.mode=mode features.mode=mode - local done={}
- while true do
- local redo=false
- local initializers=whatfeatures.initializers[mode]
- if initializers then
- for i=1,#initializers do
- local step=initializers[i]
+ local done={} + while true do + local redo=false + local initializers=whatfeatures.initializers[mode] + if initializers then + for i=1,#initializers do + local step=initializers[i] local feature=step.name - local value=features[feature]
+ local value=features[feature] if not value then elseif done[feature] then - else
- local action=step.action
- if trace then
- report("initializing feature %a to %a for mode %a for font %a",feature,
- value,mode,tfmdata.properties.fullname)
- end
+ else + local action=step.action + if trace then + report("initializing feature %a to %a for mode %a for font %a",feature, + value,mode,tfmdata.properties.fullname) + end action(tfmdata,value,features) - if mode~=properties.mode or mode~=features.mode then
- if whatmodechecker then
+ if mode~=properties.mode or mode~=features.mode then + if whatmodechecker then properties.mode=whatmodechecker(tfmdata,features,properties.mode) - features.mode=properties.mode
- end
- if mode~=properties.mode then
- mode=properties.mode
- redo=true
- end
- end
- done[feature]=true
- end
- if redo then
- break
- end
- end
- if not redo then
- break
- end
- else
- break
- end
- end
+ features.mode=properties.mode + end + if mode~=properties.mode then + mode=properties.mode + redo=true + end + end + done[feature]=true + end + if redo then + break + end + end + if not redo then + break + end + else + break + end + end properties.mode=mode - return true
- else
- return false
- end
-end -function constructors.collectprocessors(what,tfmdata,features,trace,report)
- local processes,nofprocesses={},0
- if features and next(features) then
- local properties=tfmdata.properties
- local whathandler=handlers[what]
- local whatfeatures=whathandler.features
- local whatprocessors=whatfeatures.processors
- local processors=whatprocessors[properties.mode]
- if processors then
- for i=1,#processors do
- local step=processors[i]
- local feature=step.name
- if features[feature] then
- local action=step.action
- if trace then
- report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname)
- end
- if action then
- nofprocesses=nofprocesses+1
- processes[nofprocesses]=action
- end
- end
- end
- elseif trace then
- report("no feature processors for mode %a for font %a",mode,tfmdata.properties.fullname)
- end
- end
- return processes
-end -function constructors.applymanipulators(what,tfmdata,features,trace,report)
- if features and next(features) then
- local properties=tfmdata.properties
- local whathandler=handlers[what]
- local whatfeatures=whathandler.features
- local whatmanipulators=whatfeatures.manipulators
- local manipulators=whatmanipulators[properties.mode]
- if manipulators then
- for i=1,#manipulators do
- local step=manipulators[i]
- local feature=step.name
- local value=features[feature]
- if value then
- local action=step.action
- if trace then
- report("applying feature manipulator %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname)
- end
- if action then
- action(tfmdata,feature,value)
- end
- end
- end
- end
- end
-end
+ return true + else + return false + end +end +function constructors.collectprocessors(what,tfmdata,features,trace,report) + local processes,nofprocesses={},0 + if features and next(features) then + local properties=tfmdata.properties + local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatprocessors=whatfeatures.processors + local processors=whatprocessors[properties.mode] + if processors then + for i=1,#processors do + local step=processors[i] + local feature=step.name + if features[feature] then + local action=step.action + if trace then + report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) + end + if action then + nofprocesses=nofprocesses+1 + processes[nofprocesses]=action + end + end + end + elseif trace then + report("no feature processors for mode %a for font %a",mode,tfmdata.properties.fullname) + end + end + return processes +end +function constructors.applymanipulators(what,tfmdata,features,trace,report) + if features and next(features) then + local properties=tfmdata.properties + local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatmanipulators=whatfeatures.manipulators + local manipulators=whatmanipulators[properties.mode] + if manipulators then + for i=1,#manipulators do + local step=manipulators[i] + local feature=step.name + local value=features[feature] + if value then + local action=step.action + if trace then + report("applying feature manipulator %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) + end + if action then + action(tfmdata,feature,value) + end + end + end + end + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-font-enc']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-font-enc']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
-fonts.encodings={}
+local fonts=fonts +fonts.encodings={} fonts.encodings.agl={} -setmetatable(fonts.encodings.agl,{ __index=function(t,k)
- if k=="unicodes" then
- texio.write(" <loading (extended) adobe glyph list>")
- local unicodes=dofile(resolvers.findfile("font-age.lua"))
- fonts.encodings.agl={ unicodes=unicodes }
- return unicodes
- else
- return nil
- end
+setmetatable(fonts.encodings.agl,{ __index=function(t,k) + if k=="unicodes" then + texio.write(" <loading (extended) adobe glyph list>") + local unicodes=dofile(resolvers.findfile("font-age.lua")) + fonts.encodings.agl={ unicodes=unicodes } + return unicodes + else + return nil + end end }) end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-cid']={
- version=1.001,
- comment="companion to font-otf.lua (cidmaps)",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['font-cid']={ + version=1.001, + comment="companion to font-otf.lua (cidmaps)", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local format,match,lower=string.format,string.match,string.lower
-local tonumber=tonumber
+local format,match,lower=string.format,string.match,string.lower +local tonumber=tonumber local P,S,R,C,V,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.match local fonts,logs,trackers=fonts,logs,trackers local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) local report_otf=logs.reporter("fonts","otf loading") -local cid={}
+local cid={} fonts.cid=cid -local cidmap={}
+local cidmap={} local cidmax=10 -local number=C(R("09","af","AF")^1)
-local space=S(" \n\r\t")
-local spaces=space^0
-local period=P(".")
-local periods=period*period
+local number=C(R("09","af","AF")^1) +local space=S(" \n\r\t") +local spaces=space^0 +local period=P(".") +local periods=period*period local name=P("/")*C((1-space)^1) local unicodes,names={},{} -local function do_one(a,b)
- unicodes[tonumber(a)]=tonumber(b,16)
-end -local function do_range(a,b,c)
- c=tonumber(c,16)
- for i=tonumber(a),tonumber(b) do
- unicodes[i]=c
- c=c+1
- end
-end -local function do_name(a,b)
- names[tonumber(a)]=b
-end -local grammar=P { "start",
- start=number*spaces*number*V("series"),
- series=(spaces*(V("one")+V("range")+V("named")))^1,
- one=(number*spaces*number)/do_one,
- range=(number*periods*number*spaces*number)/do_range,
- named=(number*spaces*name)/do_name
+local function do_one(a,b) + unicodes[tonumber(a)]=tonumber(b,16) +end +local function do_range(a,b,c) + c=tonumber(c,16) + for i=tonumber(a),tonumber(b) do + unicodes[i]=c + c=c+1 + end +end +local function do_name(a,b) + names[tonumber(a)]=b +end +local grammar=P { "start", + start=number*spaces*number*V("series"), + series=(spaces*(V("one")+V("range")+V("named")))^1, + one=(number*spaces*number)/do_one, + range=(number*periods*number*spaces*number)/do_range, + named=(number*spaces*name)/do_name } -local function loadcidfile(filename)
- local data=io.loaddata(filename)
- if data then
- unicodes,names={},{}
- lpegmatch(grammar,data)
- local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$")
- return {
- supplement=supplement,
- registry=registry,
- ordering=ordering,
- filename=filename,
- unicodes=unicodes,
- names=names
- }
- end
+local function loadcidfile(filename) + local data=io.loaddata(filename) + if data then + unicodes,names={},{} + lpegmatch(grammar,data) + local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$") + return { + supplement=supplement, + registry=registry, + ordering=ordering, + filename=filename, + unicodes=unicodes, + names=names + } + end end cid.loadfile=loadcidfile local template="%s-%s-%s.cidmap" -local function locate(registry,ordering,supplement)
- local filename=format(template,registry,ordering,supplement)
- local hashname=lower(filename)
- local found=cidmap[hashname]
- if not found then
- if trace_loading then
- report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename)
- end
- local fullname=resolvers.findfile(filename,'cid') or ""
- if fullname~="" then
- found=loadcidfile(fullname)
- if found then
- if trace_loading then
- report_otf("using cidmap file %a",filename)
- end
- cidmap[hashname]=found
- found.usedname=file.basename(filename)
- end
- end
- end
- return found
-end -function cid.getmap(specification)
- if not specification then
- report_otf("invalid cidinfo specification, table expected")
- return
- end
- local registry=specification.registry
- local ordering=specification.ordering
+local function locate(registry,ordering,supplement) + local filename=format(template,registry,ordering,supplement) + local hashname=lower(filename) + local found=cidmap[hashname] + if not found then + if trace_loading then + report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename) + end + local fullname=resolvers.findfile(filename,'cid') or "" + if fullname~="" then + found=loadcidfile(fullname) + if found then + if trace_loading then + report_otf("using cidmap file %a",filename) + end + cidmap[hashname]=found + found.usedname=file.basename(filename) + end + end + end + return found +end +function cid.getmap(specification) + if not specification then + report_otf("invalid cidinfo specification, table expected") + return + end + local registry=specification.registry + local ordering=specification.ordering local supplement=specification.supplement - local filename=format(registry,ordering,supplement)
- local found=cidmap[lower(filename)]
- if found then
- return found
- end
- if trace_loading then
- report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement)
- end
- found=locate(registry,ordering,supplement)
- if not found then
- local supnum=tonumber(supplement)
+ local filename=format(registry,ordering,supplement) + local found=cidmap[lower(filename)] + if found then + return found + end + if trace_loading then + report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement) + end + found=locate(registry,ordering,supplement) + if not found then + local supnum=tonumber(supplement) local cidnum=nil - if supnum<cidmax then
- for s=supnum+1,cidmax do
- local c=locate(registry,ordering,s)
- if c then
- found,cidnum=c,s
- break
- end
- end
- end - if not found and supnum>0 then
- for s=supnum-1,0,-1 do
- local c=locate(registry,ordering,s)
- if c then
- found,cidnum=c,s
- break
- end
- end
- end - registry=lower(registry)
- ordering=lower(ordering)
- if found and cidnum>0 then
- for s=0,cidnum-1 do
- local filename=format(template,registry,ordering,s)
- if not cidmap[filename] then
- cidmap[filename]=found
- end
- end
- end
- end
- return found
-end
+ if supnum<cidmax then + for s=supnum+1,cidmax do + local c=locate(registry,ordering,s) + if c then + found,cidnum=c,s + break + end + end + end + if not found and supnum>0 then + for s=supnum-1,0,-1 do + local c=locate(registry,ordering,s) + if c then + found,cidnum=c,s + break + end + end + end + registry=lower(registry) + ordering=lower(ordering) + if found and cidnum>0 then + for s=0,cidnum-1 do + local filename=format(template,registry,ordering,s) + if not cidmap[filename] then + cidmap[filename]=found + end + end + end + end + return found +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-map']={
- 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"
+if not modules then modules={} end modules ['font-map']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tonumber=tonumber -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 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 trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end)
+local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end) local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_unimapping=v end) local report_fonts=logs.reporter("fonts","loading") -local fonts=fonts or {}
-local mappings=fonts.mappings or {}
+local fonts=fonts or {} +local mappings=fonts.mappings or {} fonts.mappings=mappings local function loadlumtable(filename) - local lumname=file.replacesuffix(file.basename(filename),"lum")
- local lumfile=resolvers.findfile(lumname,"map") or ""
- if lumfile~="" and lfs.isfile(lumfile) then
- if trace_loading or trace_mapping then
- report_fonts("loading map table %a",lumfile)
- end
- lumunic=dofile(lumfile)
- return lumunic,lumfile
- end
-end -local hex=R("AF","09")
-local hexfour=(hex*hex*hex*hex)/function(s) return tonumber(s,16) end
-local hexsix=(hex*hex*hex*hex*hex*hex)/function(s) return tonumber(s,16) end
-local dec=(R("09")^1)/tonumber
-local period=P(".")
-local unicode=P("uni")*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true))
-local ucode=P("u")*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true))
+ local lumname=file.replacesuffix(file.basename(filename),"lum") + local lumfile=resolvers.findfile(lumname,"map") or "" + if lumfile~="" and lfs.isfile(lumfile) then + if trace_loading or trace_mapping then + report_fonts("loading map table %a",lumfile) + end + lumunic=dofile(lumfile) + return lumunic,lumfile + end +end +local hex=R("AF","09") +local hexfour=(hex*hex*hex*hex)/function(s) return tonumber(s,16) end +local hexsix=(hex*hex*hex*hex*hex*hex)/function(s) return tonumber(s,16) end +local dec=(R("09")^1)/tonumber +local period=P(".") +local unicode=P("uni")*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) +local ucode=P("u")*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) local index=P("index")*dec*Cc(false) local parser=unicode+ucode+index local parsers={} -local function makenameparser(str)
- if not str or str=="" then
- return parser
- else
- local p=parsers[str]
- if not p then
- p=P(str)*period*dec*Cc(false)
- parsers[str]=p
- end
- return p
- end
-end -local function tounicode16(unicode,name)
- if unicode<0x10000 then
- return format("%04X",unicode)
- elseif unicode<0x1FFFFFFFFF then
- return format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00)
- else
- report_fonts("can't convert %a in %a into tounicode",unicode,name)
- end
-end -local function tounicode16sequence(unicodes,name)
- local t={}
- for l=1,#unicodes do
- local unicode=unicodes[l]
- if unicode<0x10000 then
- t[l]=format("%04X",unicode)
- elseif unicode<0x1FFFFFFFFF then
- t[l]=format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00)
- else
- report_fonts ("can't convert %a in %a into tounicode",unicode,name)
- end
- end
- return concat(t)
-end -local function fromunicode16(str)
- if #str==4 then
- return tonumber(str,16)
- else
- local l,r=match(str,"(....)(....)")
- return (tonumber(l,16))*0x400+tonumber(r,16)-0xDC00
- end
-end -mappings.loadlumtable=loadlumtable
-mappings.makenameparser=makenameparser
-mappings.tounicode16=tounicode16
-mappings.tounicode16sequence=tounicode16sequence
+local function makenameparser(str) + if not str or str=="" then + return parser + else + local p=parsers[str] + if not p then + p=P(str)*period*dec*Cc(false) + parsers[str]=p + end + return p + end +end +local function tounicode16(unicode,name) + if unicode<0x10000 then + return format("%04X",unicode) + elseif unicode<0x1FFFFFFFFF then + return format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + else + report_fonts("can't convert %a in %a into tounicode",unicode,name) + end +end +local function tounicode16sequence(unicodes,name) + local t={} + for l=1,#unicodes do + local unicode=unicodes[l] + if unicode<0x10000 then + t[l]=format("%04X",unicode) + elseif unicode<0x1FFFFFFFFF then + t[l]=format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + else + report_fonts ("can't convert %a in %a into tounicode",unicode,name) + end + end + return concat(t) +end +local function fromunicode16(str) + if #str==4 then + return tonumber(str,16) + else + local l,r=match(str,"(....)(....)") + return (tonumber(l,16))*0x400+tonumber(r,16)-0xDC00 + end +end +mappings.loadlumtable=loadlumtable +mappings.makenameparser=makenameparser +mappings.tounicode16=tounicode16 +mappings.tounicode16sequence=tounicode16sequence mappings.fromunicode16=fromunicode16 -local separator=S("_.")
-local other=C((1-separator)^1)
+local separator=S("_.") +local other=C((1-separator)^1) local ligsplitter=Ct(other*(separator*other)^0) -function mappings.addtounicode(data,filename)
- local resources=data.resources
- local properties=data.properties
- local descriptions=data.descriptions
- local unicodes=resources.unicodes
- if not unicodes then
- return
- end - unicodes['space']=unicodes['space'] or 32
- unicodes['hyphen']=unicodes['hyphen'] or 45
- unicodes['zwj']=unicodes['zwj'] or 0x200D
+function mappings.addtounicode(data,filename) + local resources=data.resources + local properties=data.properties + local descriptions=data.descriptions + local unicodes=resources.unicodes + if not unicodes then + return + end + unicodes['space']=unicodes['space'] or 32 + unicodes['hyphen']=unicodes['hyphen'] or 45 + unicodes['zwj']=unicodes['zwj'] or 0x200D unicodes['zwnj']=unicodes['zwnj'] or 0x200C - local private=fonts.constructors.privateoffset
- local unknown=format("%04X",utfbyte("?"))
+ local private=fonts.constructors.privateoffset + local unknown=format("%04X",utfbyte("?")) local unicodevector=fonts.encodings.agl.unicodes - local tounicode={}
- local originals={}
- resources.tounicode=tounicode
- resources.originals=originals
- local lumunic,uparser,oparser
- local cidinfo,cidnames,cidcodes,usedmap
+ local tounicode={} + local originals={} + resources.tounicode=tounicode + resources.originals=originals + local lumunic,uparser,oparser + local cidinfo,cidnames,cidcodes,usedmap if false then - lumunic=loadlumtable(filename)
- lumunic=lumunic and lumunic.tounicode
+ lumunic=loadlumtable(filename) + lumunic=lumunic and lumunic.tounicode end - cidinfo=properties.cidinfo
+ cidinfo=properties.cidinfo usedmap=cidinfo and fonts.cid.getmap(cidinfo) - if usedmap then
- oparser=usedmap and makenameparser(cidinfo.ordering)
- cidnames=usedmap.names
- cidcodes=usedmap.unicodes
- end
- uparser=makenameparser()
- local ns,nl=0,0
- for unic,glyph in next,descriptions do
- local index=glyph.index
- local name=glyph.name
- if unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then
- local unicode=lumunic and lumunic[name] or unicodevector[name]
- if unicode then
- originals[index]=unicode
- tounicode[index]=tounicode16(unicode,name)
- ns=ns+1
- end - if (not unicode) and usedmap then
- local foundindex=lpegmatch(oparser,name)
- if foundindex then
+ if usedmap then + oparser=usedmap and makenameparser(cidinfo.ordering) + cidnames=usedmap.names + cidcodes=usedmap.unicodes + end + uparser=makenameparser() + local ns,nl=0,0 + for unic,glyph in next,descriptions do + local index=glyph.index + local name=glyph.name + if unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then + local unicode=lumunic and lumunic[name] or unicodevector[name] + if unicode then + originals[index]=unicode + tounicode[index]=tounicode16(unicode,name) + ns=ns+1 + end + if (not unicode) and usedmap then + local foundindex=lpegmatch(oparser,name) + if foundindex then unicode=cidcodes[foundindex] - if unicode then
- originals[index]=unicode
- tounicode[index]=tounicode16(unicode,name)
- ns=ns+1
- else
+ if unicode then + originals[index]=unicode + tounicode[index]=tounicode16(unicode,name) + ns=ns+1 + else local reference=cidnames[foundindex] - if reference then
- local foundindex=lpegmatch(oparser,reference)
- if foundindex then
- unicode=cidcodes[foundindex]
- if unicode then
- originals[index]=unicode
- tounicode[index]=tounicode16(unicode,name)
- ns=ns+1
- end
- end
- if not unicode or unicode=="" then
- local foundcodes,multiple=lpegmatch(uparser,reference)
- if foundcodes then
- originals[index]=foundcodes
- if multiple then
- tounicode[index]=tounicode16sequence(foundcodes)
- nl=nl+1
- unicode=true
- else
- tounicode[index]=tounicode16(foundcodes,name)
- ns=ns+1
- unicode=foundcodes
- end
- end
- end
- end
- end
- end
- end - if not unicode or unicode=="" then
- local split=lpegmatch(ligsplitter,name)
- local nplit=split and #split or 0
- if nplit>=2 then
- local t,n={},0
- for l=1,nplit do
- local base=split[l]
- local u=unicodes[base] or unicodevector[base]
- if not u then
- break
- elseif type(u)=="table" then
- n=n+1
- t[n]=u[1]
- else
- n=n+1
- t[n]=u
- end
- end
+ if reference then + local foundindex=lpegmatch(oparser,reference) + if foundindex then + unicode=cidcodes[foundindex] + if unicode then + originals[index]=unicode + tounicode[index]=tounicode16(unicode,name) + ns=ns+1 + end + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,reference) + if foundcodes then + originals[index]=foundcodes + if multiple then + tounicode[index]=tounicode16sequence(foundcodes) + nl=nl+1 + unicode=true + else + tounicode[index]=tounicode16(foundcodes,name) + ns=ns+1 + unicode=foundcodes + end + end + end + end + end + end + end + if not unicode or unicode=="" then + local split=lpegmatch(ligsplitter,name) + local nplit=split and #split or 0 + if nplit>=2 then + local t,n={},0 + for l=1,nplit do + local base=split[l] + local u=unicodes[base] or unicodevector[base] + if not u then + break + elseif type(u)=="table" then + n=n+1 + t[n]=u[1] + else + n=n+1 + t[n]=u + end + end if n==0 then - elseif n==1 then
- originals[index]=t[1]
- tounicode[index]=tounicode16(t[1],name)
- else
- originals[index]=t
- tounicode[index]=tounicode16sequence(t)
- end
- nl=nl+1
- unicode=true
+ elseif n==1 then + originals[index]=t[1] + tounicode[index]=tounicode16(t[1],name) + else + originals[index]=t + tounicode[index]=tounicode16sequence(t) + end + nl=nl+1 + unicode=true else - end
- end - if not unicode or unicode=="" then
- local foundcodes,multiple=lpegmatch(uparser,name)
- if foundcodes then
- if multiple then
- originals[index]=foundcodes
- tounicode[index]=tounicode16sequence(foundcodes,name)
- nl=nl+1
- unicode=true
- else
- originals[index]=foundcodes
- tounicode[index]=tounicode16(foundcodes,name)
- ns=ns+1
- unicode=foundcodes
- end
- end
- end - end
- end
- if trace_mapping then
- for unic,glyph in table.sortedhash(descriptions) do
- local name=glyph.name
- local index=glyph.index
- local toun=tounicode[index]
- if toun then
- report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun)
- else
- report_fonts("internal slot %U, name %a, unicode %U",index,name,unic)
- end
- end
- end
- if trace_loading and (ns>0 or nl>0) then
- report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns)
- end
-end
+ end + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,name) + if foundcodes then + if multiple then + originals[index]=foundcodes + tounicode[index]=tounicode16sequence(foundcodes,name) + nl=nl+1 + unicode=true + else + originals[index]=foundcodes + tounicode[index]=tounicode16(foundcodes,name) + ns=ns+1 + unicode=foundcodes + end + end + end + end + end + if trace_mapping then + for unic,glyph in table.sortedhash(descriptions) do + local name=glyph.name + local index=glyph.index + local toun=tounicode[index] + if toun then + report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun) + else + report_fonts("internal slot %U, name %a, unicode %U",index,name,unic) + end + end + end + if trace_loading and (ns>0 or nl>0) then + report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns) + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-syn']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-syn']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
+local fonts=fonts fonts.names=fonts.names or {} fonts.names.version=1.001 -fonts.names.basename="luatex-fonts-names"
-fonts.names.new_to_old={}
-fonts.names.old_to_new={}
+fonts.names.basename="luatex-fonts-names" +fonts.names.new_to_old={} +fonts.names.old_to_new={} fonts.names.cache=containers.define("fonts","data",fonts.names.version,true) local data,loaded=nil,false local fileformats={ "lua","tex","other text files" } -function fonts.names.reportmissingbase()
- texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>")
- fonts.names.reportmissingbase=nil
-end -function fonts.names.reportmissingname()
- texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>")
- fonts.names.reportmissingname=nil
-end -function fonts.names.resolve(name,sub)
- if not loaded then
- local basename=fonts.names.basename
- if basename and basename~="" then
- data=containers.read(fonts.names.cache,basename)
- if not data then
- basename=file.addsuffix(basename,"lua")
- for i=1,#fileformats do
- local format=fileformats[i]
- local foundname=resolvers.findfile(basename,format) or ""
- if foundname~="" then
- data=dofile(foundname)
- texio.write("<font database loaded: ",foundname,">")
- break
- end
- end
- end
- end
- loaded=true
- end
- if type(data)=="table" and data.version==fonts.names.version then
- local condensed=string.gsub(string.lower(name),"[^%a%d]","")
- local found=data.mappings and data.mappings[condensed]
- if found then
- local fontname,filename,subfont=found[1],found[2],found[3]
- if subfont then
- return filename,fontname
- else
- return filename,false
- end
- elseif fonts.names.reportmissingname then
- fonts.names.reportmissingname()
+function fonts.names.reportmissingbase() + texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>") + fonts.names.reportmissingbase=nil +end +function fonts.names.reportmissingname() + texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>") + fonts.names.reportmissingname=nil +end +function fonts.names.resolve(name,sub) + if not loaded then + local basename=fonts.names.basename + if basename and basename~="" then + data=containers.read(fonts.names.cache,basename) + if not data then + basename=file.addsuffix(basename,"lua") + for i=1,#fileformats do + local format=fileformats[i] + local foundname=resolvers.findfile(basename,format) or "" + if foundname~="" then + data=dofile(foundname) + texio.write("<font database loaded: ",foundname,">") + break + end + end + end + end + loaded=true + end + if type(data)=="table" and data.version==fonts.names.version then + local condensed=string.gsub(string.lower(name),"[^%a%d]","") + local found=data.mappings and data.mappings[condensed] + if found then + local fontname,filename,subfont=found[1],found[2],found[3] + if subfont then + return filename,fontname + else + return filename,false + end + elseif fonts.names.reportmissingname then + fonts.names.reportmissingname() return name,false - end
- elseif fonts.names.reportmissingbase then
- fonts.names.reportmissingbase()
- end
+ end + elseif fonts.names.reportmissingbase then + fonts.names.reportmissingbase() + end end fonts.names.resolvespec=fonts.names.resolve function fonts.names.getfilename(askedname,suffix) - return ""
-end
+ return "" +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-tfm']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-tfm']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
-local tfm={}
-fonts.handlers.tfm=tfm
+local fonts=fonts +local tfm={} +fonts.handlers.tfm=tfm fonts.formats.tfm="type1" -function fonts.readers.tfm(specification)
- local fullname=specification.filename or ""
- if fullname=="" then
- local forced=specification.forced or ""
- if forced~="" then
- fullname=specification.name.."."..forced
- else
- fullname=specification.name
- end
- end
- local foundname=resolvers.findbinfile(fullname,'tfm') or ""
- if foundname=="" then
- foundname=resolvers.findbinfile(fullname,'ofm') or ""
- end
- if foundname~="" then
- specification.filename=foundname
- specification.format="ofm"
- return font.read_tfm(specification.filename,specification.size)
- end
-end
+function fonts.readers.tfm(specification) + local fullname=specification.filename or "" + if fullname=="" then + local forced=specification.forced or "" + if forced~="" then + fullname=specification.name.."."..forced + else + fullname=specification.name + end + end + local foundname=resolvers.findbinfile(fullname,'tfm') or "" + if foundname=="" then + foundname=resolvers.findbinfile(fullname,'ofm') or "" + end + if foundname~="" then + specification.filename=foundname + specification.format="ofm" + return font.read_tfm(specification.filename,specification.size) + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-oti']={
- version=1.001,
- comment="companion to font-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['font-oti']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local lower=string.lower -local fonts=fonts
+local fonts=fonts local constructors=fonts.constructors -local otf=constructors.newhandler("otf")
-local otffeatures=constructors.newfeatures("otf")
-local otftables=otf.tables
+local otf=constructors.newhandler("otf") +local otffeatures=constructors.newfeatures("otf") +local otftables=otf.tables local registerotffeature=otffeatures.register local allocate=utilities.storage.allocate -registerotffeature {
- name="features",
- description="initialization of feature handler",
- default=true,
+registerotffeature { + name="features", + description="initialization of feature handler", + default=true, } -local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode=lower(value)
- end
-end -local function setlanguage(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local languages=otftables and otftables.languages
- local properties=tfmdata.properties
- if not languages then
- properties.language=cleanvalue
- elseif languages[value] then
- properties.language=cleanvalue
- else
- properties.language="dflt"
- end
- end
-end -local function setscript(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local scripts=otftables and otftables.scripts
- local properties=tfmdata.properties
- if not scripts then
- properties.script=cleanvalue
- elseif scripts[value] then
- properties.script=cleanvalue
- else
- properties.script="dflt"
- end
- end
-end -registerotffeature {
- name="mode",
- description="mode",
- initializers={
- base=setmode,
- node=setmode,
- }
+local function setmode(tfmdata,value) + if value then + tfmdata.properties.mode=lower(value) + end +end +local function setlanguage(tfmdata,value) + if value then + local cleanvalue=lower(value) + local languages=otftables and otftables.languages + local properties=tfmdata.properties + if not languages then + properties.language=cleanvalue + elseif languages[value] then + properties.language=cleanvalue + else + properties.language="dflt" + end + end +end +local function setscript(tfmdata,value) + if value then + local cleanvalue=lower(value) + local scripts=otftables and otftables.scripts + local properties=tfmdata.properties + if not scripts then + properties.script=cleanvalue + elseif scripts[value] then + properties.script=cleanvalue + else + properties.script="dflt" + end + end +end +registerotffeature { + name="mode", + description="mode", + initializers={ + base=setmode, + node=setmode, + } } -registerotffeature {
- name="language",
- description="language",
- initializers={
- base=setlanguage,
- node=setlanguage,
- }
+registerotffeature { + name="language", + description="language", + initializers={ + base=setlanguage, + node=setlanguage, + } } -registerotffeature {
- name="script",
- description="script",
- initializers={
- base=setscript,
- node=setscript,
- }
+registerotffeature { + name="script", + description="script", + initializers={ + base=setscript, + node=setscript, + } } end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-otf']={
- 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"
+if not modules then modules={} end modules ['font-otf']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local utfbyte=utf.byte
-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=type,next,tonumber,tostring
-local abs=math.abs
-local getn=table.getn
-local lpegmatch=lpeg.match
-local reversed,concat,remove=table.reversed,table.concat,table.remove
-local ioflush=io.flush
-local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive
+local utfbyte=utf.byte +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=type,next,tonumber,tostring +local abs=math.abs +local getn=table.getn +local lpegmatch=lpeg.match +local reversed,concat,remove=table.reversed,table.concat,table.remove +local ioflush=io.flush +local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive local formatters=string.formatters -local allocate=utilities.storage.allocate
-local registertracker=trackers.register
-local registerdirective=directives.register
-local starttiming=statistics.starttiming
-local stoptiming=statistics.stoptiming
-local elapsedtime=statistics.elapsedtime
+local allocate=utilities.storage.allocate +local registertracker=trackers.register +local registerdirective=directives.register +local starttiming=statistics.starttiming +local stoptiming=statistics.stoptiming +local elapsedtime=statistics.elapsedtime local findbinfile=resolvers.findbinfile -local trace_private=false registertracker("otf.private",function(v) trace_private=v end)
-local trace_loading=false registertracker("otf.loading",function(v) trace_loading=v end)
-local trace_features=false registertracker("otf.features",function(v) trace_features=v end)
-local trace_dynamics=false registertracker("otf.dynamics",function(v) trace_dynamics=v end)
-local trace_sequences=false registertracker("otf.sequences",function(v) trace_sequences=v end)
-local trace_markwidth=false registertracker("otf.markwidth",function(v) trace_markwidth=v end)
+local trace_private=false registertracker("otf.private",function(v) trace_private=v end) +local trace_loading=false registertracker("otf.loading",function(v) trace_loading=v end) +local trace_features=false registertracker("otf.features",function(v) trace_features=v end) +local trace_dynamics=false registertracker("otf.dynamics",function(v) trace_dynamics=v end) +local trace_sequences=false registertracker("otf.sequences",function(v) trace_sequences=v end) +local trace_markwidth=false registertracker("otf.markwidth",function(v) trace_markwidth=v end) local trace_defining=false registertracker("fonts.defining",function(v) trace_defining=v end) local report_otf=logs.reporter("fonts","otf loading") -local fonts=fonts
+local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } otf.version=2.743 otf.cache=containers.define("fonts","otf",otf.version,true) -local fontdata=fonts.hashes.identifiers
+local fontdata=fonts.hashes.identifiers local chardata=characters and characters.data -local otffeatures=fonts.constructors.newfeatures("otf")
+local otffeatures=fonts.constructors.newfeatures("otf") local registerotffeature=otffeatures.register -local enhancers=allocate()
-otf.enhancers=enhancers
-local patches={}
+local enhancers=allocate() +otf.enhancers=enhancers +local patches={} enhancers.patches=patches -local definers=fonts.definers
-local readers=fonts.readers
+local definers=fonts.definers +local readers=fonts.readers local constructors=fonts.constructors -local forceload=false
+local forceload=false local cleanup=0 local usemetatables=false -local packdata=true
-local syncspace=true
-local forcenotdef=false
+local packdata=true +local syncspace=true +local forcenotdef=false local includesubfonts=false -local wildcard="*"
+local wildcard="*" local default="dflt" -local fontloaderfields=fontloader.fields
-local mainfields=nil
+local fontloaderfields=fontloader.fields +local mainfields=nil local glyphfields=nil -registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end)
-registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
-registerdirective("fonts.otf.loader.usemetatables",function(v) usemetatables=v end)
-registerdirective("fonts.otf.loader.pack",function(v) packdata=v end)
-registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
+registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end) +registerdirective("fonts.otf.loader.force",function(v) forceload=v end) +registerdirective("fonts.otf.loader.usemetatables",function(v) usemetatables=v end) +registerdirective("fonts.otf.loader.pack",function(v) packdata=v end) +registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end) registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end) -local function load_featurefile(raw,featurefile)
- if featurefile and featurefile~="" then
- if trace_loading then
- report_otf("using featurefile %a",featurefile)
- end
- fontloader.apply_featurefile(raw,featurefile)
- end
-end -local function showfeatureorder(rawdata,filename)
- local sequences=rawdata.resources.sequences
- if sequences and #sequences>0 then
- if trace_loading then
- report_otf("font %a has %s sequences",filename,#sequences)
- report_otf(" ")
- end
- for nos=1,#sequences do
- local sequence=sequences[nos]
- local typ=sequence.type or "no-type"
- local name=sequence.name or "no-name"
- local subtables=sequence.subtables or { "no-subtables" }
- local features=sequence.features
- if trace_loading then
- report_otf("%3i %-15s %-20s [% t]",nos,name,typ,subtables)
- end
- if features then
- for feature,scripts in next,features do
- local tt={}
- if type(scripts)=="table" then
- for script,languages in next,scripts do
- local ttt={}
- for language,_ in next,languages do
- ttt[#ttt+1]=language
- end
- tt[#tt+1]=formatters["[%s: % t]"](script,ttt)
- end
- if trace_loading then
- report_otf(" %s: % t",feature,tt)
- end
- else
- if trace_loading then
- report_otf(" %s: %S",feature,scripts)
- end
- end
- end
- end
- end
- if trace_loading then
- report_otf("\n")
- end
- elseif trace_loading then
- report_otf("font %a has no sequences",filename)
- end
+local function load_featurefile(raw,featurefile) + if featurefile and featurefile~="" then + if trace_loading then + report_otf("using featurefile %a",featurefile) + end + fontloader.apply_featurefile(raw,featurefile) + end +end +local function showfeatureorder(rawdata,filename) + local sequences=rawdata.resources.sequences + if sequences and #sequences>0 then + if trace_loading then + report_otf("font %a has %s sequences",filename,#sequences) + report_otf(" ") + end + for nos=1,#sequences do + local sequence=sequences[nos] + local typ=sequence.type or "no-type" + local name=sequence.name or "no-name" + local subtables=sequence.subtables or { "no-subtables" } + local features=sequence.features + if trace_loading then + report_otf("%3i %-15s %-20s [% t]",nos,name,typ,subtables) + end + if features then + for feature,scripts in next,features do + local tt={} + if type(scripts)=="table" then + for script,languages in next,scripts do + local ttt={} + for language,_ in next,languages do + ttt[#ttt+1]=language + end + tt[#tt+1]=formatters["[%s: % t]"](script,ttt) + end + if trace_loading then + report_otf(" %s: % t",feature,tt) + end + else + if trace_loading then + report_otf(" %s: %S",feature,scripts) + end + end + end + end + end + if trace_loading then + report_otf("\n") + end + elseif trace_loading then + report_otf("font %a has no sequences",filename) + end end local valid_fields=table.tohash { "ascent", - "cidinfo",
+ "cidinfo", "copyright", - "descent",
- "design_range_bottom",
- "design_range_top",
- "design_size",
- "encodingchanged",
- "extrema_bound",
- "familyname",
- "fontname",
- "fontname",
- "fontstyle_id",
- "fontstyle_name",
+ "descent", + "design_range_bottom", + "design_range_top", + "design_size", + "encodingchanged", + "extrema_bound", + "familyname", + "fontname", + "fontname", + "fontstyle_id", + "fontstyle_name", "fullname", "hasvmetrics", - "horiz_base",
- "issans",
- "isserif",
+ "horiz_base", + "issans", + "isserif", "italicangle", "macstyle", - "onlybitmaps",
- "origname",
- "os2_version",
+ "onlybitmaps", + "origname", + "os2_version", "pfminfo", - "serifcheck",
+ "serifcheck", "sfd_version", - "strokedfont",
+ "strokedfont", "strokewidth", "table_version", - "ttf_tables",
- "uni_interp",
- "uniqueid",
- "units_per_em",
- "upos",
- "use_typo_metrics",
+ "ttf_tables", + "uni_interp", + "uniqueid", + "units_per_em", + "upos", + "use_typo_metrics", "uwidth", - "version",
- "vert_base",
- "weight",
+ "version", + "vert_base", + "weight", "weight_width_slope_only", } -local ordered_enhancers={
+local ordered_enhancers={ "prepare tables", - "prepare glyphs",
+ "prepare glyphs", "prepare lookups", - "analyze glyphs",
+ "analyze glyphs", "analyze math", "prepare tounicode", - "reorganize lookups",
- "reorganize mark classes",
+ "reorganize lookups", + "reorganize mark classes", "reorganize anchor classes", - "reorganize glyph kerns",
- "reorganize glyph lookups",
+ "reorganize glyph kerns", + "reorganize glyph lookups", "reorganize glyph anchors", "merge kern classes", - "reorganize features",
+ "reorganize features", "reorganize subtables", - "check glyphs",
- "check metadata",
+ "check glyphs", + "check metadata", "check extra features", "check encoding", "add duplicates", - "cleanup tables",
+ "cleanup tables", } -local actions=allocate()
-local before=allocate()
+local actions=allocate() +local before=allocate() local after=allocate() -patches.before=before
+patches.before=before patches.after=after -local function enhance(name,data,filename,raw)
- local enhancer=actions[name]
- if enhancer then
- if trace_loading then
- report_otf("apply enhancement %a to file %a",name,filename)
- ioflush()
- end
- enhancer(data,filename,raw)
+local function enhance(name,data,filename,raw) + local enhancer=actions[name] + if enhancer then + if trace_loading then + report_otf("apply enhancement %a to file %a",name,filename) + ioflush() + end + enhancer(data,filename,raw) else - end
+ end end -function enhancers.apply(data,filename,raw)
- local basename=file.basename(lower(filename))
- if trace_loading then
- report_otf("%s enhancing file %a","start",filename)
- end
+function enhancers.apply(data,filename,raw) + local basename=file.basename(lower(filename)) + if trace_loading then + report_otf("%s enhancing file %a","start",filename) + end ioflush() - for e=1,#ordered_enhancers do
- local enhancer=ordered_enhancers[e]
- local b=before[enhancer]
- if b then
- for pattern,action in next,b do
- if find(basename,pattern) then
- action(data,filename,raw)
- end
- end
- end
- enhance(enhancer,data,filename,raw)
- local a=after[enhancer]
- if a then
- for pattern,action in next,a do
- if find(basename,pattern) then
- action(data,filename,raw)
- end
- end
- end
+ for e=1,#ordered_enhancers do + local enhancer=ordered_enhancers[e] + local b=before[enhancer] + if b then + for pattern,action in next,b do + if find(basename,pattern) then + action(data,filename,raw) + end + end + end + enhance(enhancer,data,filename,raw) + local a=after[enhancer] + if a then + for pattern,action in next,a do + if find(basename,pattern) then + action(data,filename,raw) + end + end + end ioflush() - end
- if trace_loading then
- report_otf("%s enhancing file %a","stop",filename)
- end
+ end + if trace_loading then + report_otf("%s enhancing file %a","stop",filename) + end ioflush() end -function patches.register(what,where,pattern,action)
- local pw=patches[what]
- if pw then
- local ww=pw[where]
- if ww then
- ww[pattern]=action
- else
- pw[where]={ [pattern]=action}
- end
- end
-end -function patches.report(fmt,...)
- if trace_loading then
- report_otf("patching: %s",formatters[fmt](...))
- end
+function patches.register(what,where,pattern,action) + local pw=patches[what] + if pw then + local ww=pw[where] + if ww then + ww[pattern]=action + else + pw[where]={ [pattern]=action} + end + end +end +function patches.report(fmt,...) + if trace_loading then + report_otf("patching: %s",formatters[fmt](...)) + end end function enhancers.register(what,action) - actions[what]=action
-end -function otf.load(filename,format,sub,featurefile)
- local base=file.basename(file.removesuffix(filename))
- local name=file.removesuffix(base)
- local attr=lfs.attributes(filename)
- local size=attr and attr.size or 0
- local time=attr and attr.modification or 0
- if featurefile then
- name=name.."@"..file.removesuffix(file.basename(featurefile))
- end
- if sub=="" then
- sub=false
- end
- local hash=name
- if sub then
- hash=hash.."-"..sub
- end
- hash=containers.cleanname(hash)
- local featurefiles
- if featurefile then
- featurefiles={}
- for s in gmatch(featurefile,"[^,]+") do
- local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or ""
- if name=="" then
- report_otf("loading error, no featurefile %a",s)
- else
- local attr=lfs.attributes(name)
- featurefiles[#featurefiles+1]={
- name=name,
- size=attr and attr.size or 0,
- time=attr and attr.modification or 0,
- }
- end
- end
- if #featurefiles==0 then
- featurefiles=nil
- end
- end
- local data=containers.read(otf.cache,hash)
- local reload=not data or data.size~=size or data.time~=time
- if forceload then
- report_otf("forced reload of %a due to hard coded flag",filename)
- reload=true
- end
- if not reload then
- local featuredata=data.featuredata
- if featurefiles then
- if not featuredata or #featuredata~=#featurefiles then
- reload=true
- else
- for i=1,#featurefiles do
- local fi,fd=featurefiles[i],featuredata[i]
- if fi.name~=fd.name or fi.size~=fd.size or fi.time~=fd.time then
- reload=true
- break
- end
- end
- end
- elseif featuredata then
- reload=true
- end
- if reload then
- report_otf("loading: forced reload due to changed featurefile specification %a",featurefile)
- end
- end
- if reload then
- report_otf("loading %a, hash %a",filename,hash)
- local fontdata,messages
- if sub then
- fontdata,messages=fontloader.open(filename,sub)
- else
- fontdata,messages=fontloader.open(filename)
- end
- if fontdata then
- mainfields=mainfields or (fontloaderfields and fontloaderfields(fontdata))
- end
- if trace_loading and messages and #messages>0 then
- if type(messages)=="string" then
- report_otf("warning: %s",messages)
- else
- for m=1,#messages do
- report_otf("warning: %S",messages[m])
- end
- end
- else
- report_otf("loading done")
- end
- if fontdata then
- if featurefiles then
- for i=1,#featurefiles do
- load_featurefile(fontdata,featurefiles[i].name)
- end
- end
+ actions[what]=action +end +function otf.load(filename,format,sub,featurefile) + local base=file.basename(file.removesuffix(filename)) + local name=file.removesuffix(base) + local attr=lfs.attributes(filename) + local size=attr and attr.size or 0 + local time=attr and attr.modification or 0 + if featurefile then + name=name.."@"..file.removesuffix(file.basename(featurefile)) + end + if sub=="" then + sub=false + end + local hash=name + if sub then + hash=hash.."-"..sub + end + hash=containers.cleanname(hash) + local featurefiles + if featurefile then + featurefiles={} + for s in gmatch(featurefile,"[^,]+") do + local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or "" + if name=="" then + report_otf("loading error, no featurefile %a",s) + else + local attr=lfs.attributes(name) + featurefiles[#featurefiles+1]={ + name=name, + size=attr and attr.size or 0, + time=attr and attr.modification or 0, + } + end + end + if #featurefiles==0 then + featurefiles=nil + end + end + local data=containers.read(otf.cache,hash) + local reload=not data or data.size~=size or data.time~=time + if forceload then + report_otf("forced reload of %a due to hard coded flag",filename) + reload=true + end + if not reload then + local featuredata=data.featuredata + if featurefiles then + if not featuredata or #featuredata~=#featurefiles then + reload=true + else + for i=1,#featurefiles do + local fi,fd=featurefiles[i],featuredata[i] + if fi.name~=fd.name or fi.size~=fd.size or fi.time~=fd.time then + reload=true + break + end + end + end + elseif featuredata then + reload=true + end + if reload then + report_otf("loading: forced reload due to changed featurefile specification %a",featurefile) + end + end + if reload then + report_otf("loading %a, hash %a",filename,hash) + local fontdata,messages + if sub then + fontdata,messages=fontloader.open(filename,sub) + else + fontdata,messages=fontloader.open(filename) + end + if fontdata then + mainfields=mainfields or (fontloaderfields and fontloaderfields(fontdata)) + end + if trace_loading and messages and #messages>0 then + if type(messages)=="string" then + report_otf("warning: %s",messages) + else + for m=1,#messages do + report_otf("warning: %S",messages[m]) + end + end + else + report_otf("loading done") + end + if fontdata then + if featurefiles then + for i=1,#featurefiles do + load_featurefile(fontdata,featurefiles[i].name) + end + end local unicodes={ - }
- local splitter=lpeg.splitter(" ",unicodes)
- data={
- size=size,
- time=time,
- format=format,
- featuredata=featurefiles,
- resources={
+ } + local splitter=lpeg.splitter(" ",unicodes) + data={ + size=size, + time=time, + format=format, + featuredata=featurefiles, + resources={ filename=resolvers.unresolve(filename), - version=otf.version,
- creator="context mkiv",
- unicodes=unicodes,
+ version=otf.version, + creator="context mkiv", + unicodes=unicodes, indices={ - },
+ }, duplicates={ - },
+ }, variants={ - },
- lookuptypes={},
- },
+ }, + lookuptypes={}, + }, metadata={ - },
+ }, properties={ - },
- descriptions={},
- goodies={},
- helpers={
- tounicodelist=splitter,
- tounicodetable=lpeg.Ct(splitter),
- },
- }
- starttiming(data)
- report_otf("file size: %s",size)
- enhancers.apply(data,filename,fontdata)
- local packtime={}
- if packdata then
- if cleanup>0 then
- collectgarbage("collect")
- end
- starttiming(packtime)
- enhance("pack",data,filename,nil)
- stoptiming(packtime)
- end
- report_otf("saving %a in cache",filename)
- data=containers.write(otf.cache,hash,data)
- if cleanup>1 then
- collectgarbage("collect")
- end
- stoptiming(data)
+ }, + descriptions={}, + goodies={}, + helpers={ + tounicodelist=splitter, + tounicodetable=lpeg.Ct(splitter), + }, + } + starttiming(data) + report_otf("file size: %s",size) + enhancers.apply(data,filename,fontdata) + local packtime={} + if packdata then + if cleanup>0 then + collectgarbage("collect") + end + starttiming(packtime) + enhance("pack",data,filename,nil) + stoptiming(packtime) + end + report_otf("saving %a in cache",filename) + data=containers.write(otf.cache,hash,data) + if cleanup>1 then + collectgarbage("collect") + end + stoptiming(data) if elapsedtime then - report_otf("preprocessing and caching time %s, packtime %s",
- elapsedtime(data),packdata and elapsedtime(packtime) or 0)
- end
+ report_otf("preprocessing and caching time %s, packtime %s", + elapsedtime(data),packdata and elapsedtime(packtime) or 0) + end fontloader.close(fontdata) - if cleanup>3 then
- collectgarbage("collect")
- end
+ if cleanup>3 then + collectgarbage("collect") + end data=containers.read(otf.cache,hash) - if cleanup>2 then
- collectgarbage("collect")
- end
- else
- data=nil
- report_otf("loading failed due to read error")
- end
- end
- if data then
- if trace_defining then
- report_otf("loading from cache using hash %a",hash)
- end
- enhance("unpack",data,filename,nil,false)
- enhance("add dimensions",data,filename,nil,false)
- if trace_sequences then
- showfeatureorder(data,filename)
- end
- end
- return data
-end -local mt={
+ if cleanup>2 then + collectgarbage("collect") + end + else + data=nil + report_otf("loading failed due to read error") + end + end + if data then + if trace_defining then + report_otf("loading from cache using hash %a",hash) + end + enhance("unpack",data,filename,nil,false) + enhance("add dimensions",data,filename,nil,false) + if trace_sequences then + showfeatureorder(data,filename) + end + end + return data +end +local mt={ __index=function(t,k) - if k=="height" then
- local ht=t.boundingbox[4]
- return ht<0 and 0 or ht
- elseif k=="depth" then
- local dp=-t.boundingbox[2]
- return dp<0 and 0 or dp
- elseif k=="width" then
- return 0
+ if k=="height" then + local ht=t.boundingbox[4] + return ht<0 and 0 or ht + elseif k=="depth" then + local dp=-t.boundingbox[2] + return dp<0 and 0 or dp + elseif k=="width" then + return 0 elseif k=="name" then - return forcenotdef and ".notdef"
- end
- end
+ return forcenotdef and ".notdef" + end + end } -actions["prepare tables"]=function(data,filename,raw)
- data.properties.hasitalics=false
+actions["prepare tables"]=function(data,filename,raw) + data.properties.hasitalics=false end actions["add dimensions"]=function(data,filename) - if data then
- local descriptions=data.descriptions
- local resources=data.resources
- local defaultwidth=resources.defaultwidth or 0
- local defaultheight=resources.defaultheight or 0
- local defaultdepth=resources.defaultdepth or 0
- local basename=trace_markwidth and file.basename(filename)
- if usemetatables then
- for _,d in next,descriptions do
- local wd=d.width
- if not wd then
- d.width=defaultwidth
- elseif trace_markwidth and wd~=0 and d.class=="mark" then
+ if data then + local descriptions=data.descriptions + local resources=data.resources + local defaultwidth=resources.defaultwidth or 0 + local defaultheight=resources.defaultheight or 0 + local defaultdepth=resources.defaultdepth or 0 + local basename=trace_markwidth and file.basename(filename) + if usemetatables then + for _,d in next,descriptions do + local wd=d.width + if not wd then + d.width=defaultwidth + elseif trace_markwidth and wd~=0 and d.class=="mark" then report_otf("mark %a with width %b found in %a",d.name or "<noname>",wd,basename) - end
- setmetatable(d,mt)
- end
- else
- for _,d in next,descriptions do
- local bb,wd=d.boundingbox,d.width
- if not wd then
- d.width=defaultwidth
- elseif trace_markwidth and wd~=0 and d.class=="mark" then
+ end + setmetatable(d,mt) + end + else + for _,d in next,descriptions do + local bb,wd=d.boundingbox,d.width + if not wd then + d.width=defaultwidth + elseif trace_markwidth and wd~=0 and d.class=="mark" then report_otf("mark %a with width %b found in %a",d.name or "<noname>",wd,basename) end - if bb then
- local ht,dp=bb[4],-bb[2]
+ if bb then + local ht,dp=bb[4],-bb[2] if ht==0 or ht<0 then - else
- d.height=ht
- end
+ else + d.height=ht + end if dp==0 or dp<0 then - else
- d.depth=dp
- end
- end
- end
- end
- end
+ else + d.depth=dp + end + end + end + end + end end local function somecopy(old) - if old then
- local new={}
- if type(old)=="table" then
- for k,v in next,old do
+ if old then + local new={} + if type(old)=="table" then + for k,v in next,old do if k=="glyphs" then - elseif type(v)=="table" then
- new[k]=somecopy(v)
- else
- new[k]=v
- end
- end
- else
- for i=1,#mainfields do
- local k=mainfields[i]
- local v=old[k]
+ elseif type(v)=="table" then + new[k]=somecopy(v) + else + new[k]=v + end + end + else + for i=1,#mainfields do + local k=mainfields[i] + local v=old[k] if k=="glyphs" then - elseif type(v)=="table" then
- new[k]=somecopy(v)
- else
- new[k]=v
- end
- end
- end
- return new
- else
- return {}
- end
-end -actions["prepare glyphs"]=function(data,filename,raw)
- local rawglyphs=raw.glyphs
- local rawsubfonts=raw.subfonts
- local rawcidinfo=raw.cidinfo
- local criterium=constructors.privateoffset
- local private=criterium
- local resources=data.resources
- local metadata=data.metadata
- local properties=data.properties
- local descriptions=data.descriptions
+ elseif type(v)=="table" then + new[k]=somecopy(v) + else + new[k]=v + end + end + end + return new + else + return {} + end +end +actions["prepare glyphs"]=function(data,filename,raw) + local rawglyphs=raw.glyphs + local rawsubfonts=raw.subfonts + local rawcidinfo=raw.cidinfo + local criterium=constructors.privateoffset + local private=criterium + local resources=data.resources + local metadata=data.metadata + local properties=data.properties + local descriptions=data.descriptions local unicodes=resources.unicodes local indices=resources.indices - local duplicates=resources.duplicates
+ local duplicates=resources.duplicates local variants=resources.variants if rawsubfonts then - metadata.subfonts=includesubfonts and {}
+ metadata.subfonts=includesubfonts and {} properties.cidinfo=rawcidinfo - if rawcidinfo.registry then
- local cidmap=fonts.cid.getmap(rawcidinfo)
- if cidmap then
- rawcidinfo.usedname=cidmap.usedname
- local nofnames,nofunicodes=0,0
- local cidunicodes,cidnames=cidmap.unicodes,cidmap.names
- for cidindex=1,#rawsubfonts do
- local subfont=rawsubfonts[cidindex]
- local cidglyphs=subfont.glyphs
- if includesubfonts then
- metadata.subfonts[cidindex]=somecopy(subfont)
- end
+ if rawcidinfo.registry then + local cidmap=fonts.cid.getmap(rawcidinfo) + if cidmap then + rawcidinfo.usedname=cidmap.usedname + local nofnames,nofunicodes=0,0 + local cidunicodes,cidnames=cidmap.unicodes,cidmap.names + for cidindex=1,#rawsubfonts do + local subfont=rawsubfonts[cidindex] + local cidglyphs=subfont.glyphs + if includesubfonts then + metadata.subfonts[cidindex]=somecopy(subfont) + end for index=0,subfont.glyphcnt-1 do - local glyph=cidglyphs[index]
- if glyph then
- local unicode=glyph.unicode
- local name=glyph.name or cidnames[index]
- if not unicode or unicode==-1 or unicode>=criterium then
- unicode=cidunicodes[index]
- end
- if unicode and descriptions[unicode] then
- report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode)
- unicode=-1
- end
- if not unicode or unicode==-1 or unicode>=criterium then
- if not name then
- name=format("u%06X",private)
- end
- unicode=private
- unicodes[name]=private
- if trace_private then
- report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private)
- end
- private=private+1
- nofnames=nofnames+1
- else
- if not name then
- name=format("u%06X",unicode)
- end
- unicodes[name]=unicode
- nofunicodes=nofunicodes+1
- end
+ local glyph=cidglyphs[index] + if glyph then + local unicode=glyph.unicode + local name=glyph.name or cidnames[index] + if not unicode or unicode==-1 or unicode>=criterium then + unicode=cidunicodes[index] + end + if unicode and descriptions[unicode] then + report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) + unicode=-1 + end + if not unicode or unicode==-1 or unicode>=criterium then + if not name then + name=format("u%06X",private) + end + unicode=private + unicodes[name]=private + if trace_private then + report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private) + end + private=private+1 + nofnames=nofnames+1 + else + if not name then + name=format("u%06X",unicode) + end + unicodes[name]=unicode + nofunicodes=nofunicodes+1 + end indices[index]=unicode local description={ - boundingbox=glyph.boundingbox,
+ boundingbox=glyph.boundingbox, name=glyph.name or name or "unknown", - cidindex=cidindex,
- index=index,
- glyph=glyph,
+ cidindex=cidindex, + index=index, + glyph=glyph, } - descriptions[unicode]=description
+ descriptions[unicode]=description else - end
- end
- end
- if trace_loading then
- report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes,nofnames,nofunicodes+nofnames)
- end
- elseif trace_loading then
- report_otf("unable to remap cid font, missing cid file for %a",filename)
- end
- elseif trace_loading then
- report_otf("font %a has no glyphs",filename)
+ end + end + end + if trace_loading then + report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes,nofnames,nofunicodes+nofnames) + end + elseif trace_loading then + report_otf("unable to remap cid font, missing cid file for %a",filename) + end + elseif trace_loading then + report_otf("font %a has no glyphs",filename) end else for index=0,raw.glyphcnt-1 do - local glyph=rawglyphs[index]
- if glyph then
- local unicode=glyph.unicode
- local name=glyph.name
- if not unicode or unicode==-1 or unicode>=criterium then
- unicode=private
- unicodes[name]=private
- if trace_private then
- report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private)
- end
- private=private+1
- else
- unicodes[name]=unicode
- end
- indices[index]=unicode
- if not name then
- name=format("u%06X",unicode)
- end
+ local glyph=rawglyphs[index] + if glyph then + local unicode=glyph.unicode + local name=glyph.name + if not unicode or unicode==-1 or unicode>=criterium then + unicode=private + unicodes[name]=private + if trace_private then + report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private) + end + private=private+1 + else + unicodes[name]=unicode + end + indices[index]=unicode + if not name then + name=format("u%06X",unicode) + end descriptions[unicode]={ - boundingbox=glyph.boundingbox,
- name=name,
- index=index,
- glyph=glyph,
- }
- local altuni=glyph.altuni
- if altuni then
- local d
- for i=1,#altuni do
- local a=altuni[i]
- local u=a.unicode
- local v=a.variant
+ boundingbox=glyph.boundingbox, + name=name, + index=index, + glyph=glyph, + } + local altuni=glyph.altuni + if altuni then + local d + for i=1,#altuni do + local a=altuni[i] + local u=a.unicode + local v=a.variant if v then - local vv=variants[v]
- if vv then
- vv[u]=unicode
+ local vv=variants[v] + if vv then + vv[u]=unicode else - vv={ [u]=unicode }
- variants[v]=vv
- end
- elseif d then
- d[#d+1]=u
- else
- d={ u }
- end
- end
- if d then
- duplicates[unicode]=d
- end
- end
- else
- report_otf("potential problem: glyph %U is used but empty",index)
- end
+ vv={ [u]=unicode } + variants[v]=vv + end + elseif d then + d[#d+1]=u + else + d={ u } + end + end + if d then + duplicates[unicode]=d + end + end + else + report_otf("potential problem: glyph %U is used but empty",index) + end end end resources.private=private end -actions["check encoding"]=function(data,filename,raw)
- local descriptions=data.descriptions
- local resources=data.resources
- local properties=data.properties
+actions["check encoding"]=function(data,filename,raw) + local descriptions=data.descriptions + local resources=data.resources + local properties=data.properties local unicodes=resources.unicodes local indices=resources.indices local duplicates=resources.duplicates - local mapdata=raw.map or {}
+ local mapdata=raw.map or {} local unicodetoindex=mapdata and mapdata.map or {} - local encname=lower(data.enc_name or mapdata.enc_name or "")
+ local encname=lower(data.enc_name or mapdata.enc_name or "") local criterium=0xFFFF if find(encname,"unicode") then - if trace_loading then
- report_otf("checking embedded unicode map %a",encname)
- end
+ if trace_loading then + report_otf("checking embedded unicode map %a",encname) + end for unicode,index in next,unicodetoindex do - if unicode<=criterium and not descriptions[unicode] then
+ if unicode<=criterium and not descriptions[unicode] then local parent=indices[index] - if not parent then
- report_otf("weird, unicode %U points to nowhere with index %H",unicode,index)
- else
- local parentdescription=descriptions[parent]
- if parentdescription then
- local altuni=parentdescription.altuni
- if not altuni then
- altuni={ { unicode=parent } }
- parentdescription.altuni=altuni
- duplicates[parent]={ unicode }
- else
- local done=false
- for i=1,#altuni do
- if altuni[i].unicode==parent then
- done=true
- break
- end
- end
+ if not parent then + report_otf("weird, unicode %U points to nowhere with index %H",unicode,index) + else + local parentdescription=descriptions[parent] + if parentdescription then + local altuni=parentdescription.altuni + if not altuni then + altuni={ { unicode=parent } } + parentdescription.altuni=altuni + duplicates[parent]={ unicode } + else + local done=false + for i=1,#altuni do + if altuni[i].unicode==parent then + done=true + break + end + end if not done then - altuni[#altuni+1]={ unicode=parent }
- table.insert(duplicates[parent],unicode)
- end
- end
- if trace_loading then
- report_otf("weird, unicode %U points to nowhere with index %H",unicode,index)
- end
- else
- report_otf("weird, unicode %U points to %U with index %H",unicode,index)
- end
- end
- end
- end
- elseif properties.cidinfo then
- report_otf("warning: no unicode map, used cidmap %a",properties.cidinfo.usedname)
- else
- report_otf("warning: non unicode map %a, only using glyph unicode data",encname or "whatever")
- end - if mapdata then
+ altuni[#altuni+1]={ unicode=parent } + table.insert(duplicates[parent],unicode) + end + end + if trace_loading then + report_otf("weird, unicode %U points to nowhere with index %H",unicode,index) + end + else + report_otf("weird, unicode %U points to %U with index %H",unicode,index) + end + end + end + end + elseif properties.cidinfo then + report_otf("warning: no unicode map, used cidmap %a",properties.cidinfo.usedname) + else + report_otf("warning: non unicode map %a, only using glyph unicode data",encname or "whatever") + end + if mapdata then mapdata.map={} - end
+ end end -actions["add duplicates"]=function(data,filename,raw)
- local descriptions=data.descriptions
- local resources=data.resources
- local properties=data.properties
+actions["add duplicates"]=function(data,filename,raw) + local descriptions=data.descriptions + local resources=data.resources + local properties=data.properties local unicodes=resources.unicodes local indices=resources.indices local duplicates=resources.duplicates - for unicode,d in next,duplicates do
- for i=1,#d do
- local u=d[i]
- if not descriptions[u] then
- local description=descriptions[unicode]
+ for unicode,d in next,duplicates do + for i=1,#d do + local u=d[i] + if not descriptions[u] then + local description=descriptions[unicode] local duplicate=table.copy(description) - duplicate.comment=format("copy of U+%05X",unicode)
- descriptions[u]=duplicate
- local n=0
- for _,description in next,descriptions do
- if kerns then
- local kerns=description.kerns
- for _,k in next,kerns do
- local ku=k[unicode]
- if ku then
- k[u]=ku
- n=n+1
- end
- end
- end - end
- if trace_loading then
- report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n)
- end
- end
- end
- end
+ duplicate.comment=format("copy of U+%05X",unicode) + descriptions[u]=duplicate + local n=0 + for _,description in next,descriptions do + if kerns then + local kerns=description.kerns + for _,k in next,kerns do + local ku=k[unicode] + if ku then + k[u]=ku + n=n+1 + end + end + end + end + if trace_loading then + report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n) + end + end + end + end end actions["analyze glyphs"]=function(data,filename,raw) - local descriptions=data.descriptions
- local resources=data.resources
- local metadata=data.metadata
- local properties=data.properties
- local hasitalics=false
- local widths={}
+ local descriptions=data.descriptions + local resources=data.resources + local metadata=data.metadata + local properties=data.properties + local hasitalics=false + local widths={} local marks={} - for unicode,description in next,descriptions do
- local glyph=description.glyph
- local italic=glyph.italic_correction
+ for unicode,description in next,descriptions do + local glyph=description.glyph + local italic=glyph.italic_correction if not italic then elseif italic==0 then - else
- description.italic=italic
- hasitalics=true
- end
- local width=glyph.width
- widths[width]=(widths[width] or 0)+1
- local class=glyph.class
- if class then
- if class=="mark" then
- marks[unicode]=true
- end
- description.class=class
- end
+ else + description.italic=italic + hasitalics=true + end + local width=glyph.width + widths[width]=(widths[width] or 0)+1 + local class=glyph.class + if class then + if class=="mark" then + marks[unicode]=true + end + description.class=class + end end properties.hasitalics=hasitalics resources.marks=marks - local wd,most=0,1
- for k,v in next,widths do
- if v>most then
- wd,most=k,v
- end
- end
+ local wd,most=0,1 + for k,v in next,widths do + if v>most then + wd,most=k,v + end + end if most>1000 then - if trace_loading then
- report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most)
- end
- for unicode,description in next,descriptions do
+ if trace_loading then + report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most) + end + for unicode,description in next,descriptions do if description.width==wd then - else
- description.width=description.glyph.width
- end
- end
- resources.defaultwidth=wd
- else
- for unicode,description in next,descriptions do
- description.width=description.glyph.width
- end
- end
-end -actions["reorganize mark classes"]=function(data,filename,raw)
- local mark_classes=raw.mark_classes
- if mark_classes then
- local resources=data.resources
- local unicodes=resources.unicodes
- local markclasses={}
+ else + description.width=description.glyph.width + end + end + resources.defaultwidth=wd + else + for unicode,description in next,descriptions do + description.width=description.glyph.width + end + end +end +actions["reorganize mark classes"]=function(data,filename,raw) + local mark_classes=raw.mark_classes + if mark_classes then + local resources=data.resources + local unicodes=resources.unicodes + local markclasses={} resources.markclasses=markclasses - for name,class in next,mark_classes do
- local t={}
- for s in gmatch(class,"[^ ]+") do
- t[unicodes[s]]=true
- end
- markclasses[name]=t
- end
- end
+ for name,class in next,mark_classes do + local t={} + for s in gmatch(class,"[^ ]+") do + t[unicodes[s]]=true + end + markclasses[name]=t + end + end end actions["reorganize features"]=function(data,filename,raw) - local features={}
- data.resources.features=features
- for k,what in next,otf.glists do
- local dw=raw[what]
- if dw then
- local f={}
- features[what]=f
- for i=1,#dw do
- local d=dw[i]
- local dfeatures=d.features
- if dfeatures then
- for i=1,#dfeatures do
- local df=dfeatures[i]
- local tag=strip(lower(df.tag))
- local ft=f[tag]
- if not ft then
- ft={}
- f[tag]=ft
- end
- local dscripts=df.scripts
- for i=1,#dscripts do
- local d=dscripts[i]
- local languages=d.langs
- local script=strip(lower(d.script))
- local fts=ft[script] if not fts then fts={} ft[script]=fts end
- for i=1,#languages do
- fts[strip(lower(languages[i]))]=true
- end
- end
- end
- end
- end
- end
- end
-end -actions["reorganize anchor classes"]=function(data,filename,raw)
- local resources=data.resources
- local anchor_to_lookup={}
- local lookup_to_anchor={}
- resources.anchor_to_lookup=anchor_to_lookup
- resources.lookup_to_anchor=lookup_to_anchor
+ local features={} + data.resources.features=features + for k,what in next,otf.glists do + local dw=raw[what] + if dw then + local f={} + features[what]=f + for i=1,#dw do + local d=dw[i] + local dfeatures=d.features + if dfeatures then + for i=1,#dfeatures do + local df=dfeatures[i] + local tag=strip(lower(df.tag)) + local ft=f[tag] + if not ft then + ft={} + f[tag]=ft + end + local dscripts=df.scripts + for i=1,#dscripts do + local d=dscripts[i] + local languages=d.langs + local script=strip(lower(d.script)) + local fts=ft[script] if not fts then fts={} ft[script]=fts end + for i=1,#languages do + fts[strip(lower(languages[i]))]=true + end + end + end + end + end + end + end +end +actions["reorganize anchor classes"]=function(data,filename,raw) + local resources=data.resources + local anchor_to_lookup={} + local lookup_to_anchor={} + resources.anchor_to_lookup=anchor_to_lookup + resources.lookup_to_anchor=lookup_to_anchor local classes=raw.anchor_classes - if classes then
- for c=1,#classes do
- local class=classes[c]
- local anchor=class.name
- local lookups=class.lookup
- if type(lookups)~="table" then
- lookups={ lookups }
- end
- local a=anchor_to_lookup[anchor]
- if not a then
- a={}
- anchor_to_lookup[anchor]=a
- end
- for l=1,#lookups do
- local lookup=lookups[l]
- local l=lookup_to_anchor[lookup]
- if l then
- l[anchor]=true
- else
- l={ [anchor]=true }
- lookup_to_anchor[lookup]=l
- end
- a[lookup]=true
- end
- end
- end
-end -actions["prepare tounicode"]=function(data,filename,raw)
- fonts.mappings.addtounicode(data,filename)
-end -local g_directions={
- gsub_contextchain=1,
+ if classes then + for c=1,#classes do + local class=classes[c] + local anchor=class.name + local lookups=class.lookup + if type(lookups)~="table" then + lookups={ lookups } + end + local a=anchor_to_lookup[anchor] + if not a then + a={} + anchor_to_lookup[anchor]=a + end + for l=1,#lookups do + local lookup=lookups[l] + local l=lookup_to_anchor[lookup] + if l then + l[anchor]=true + else + l={ [anchor]=true } + lookup_to_anchor[lookup]=l + end + a[lookup]=true + end + end + end +end +actions["prepare tounicode"]=function(data,filename,raw) + fonts.mappings.addtounicode(data,filename) +end +local g_directions={ + gsub_contextchain=1, gpos_contextchain=1, - gsub_reversecontextchain=-1,
- gpos_reversecontextchain=-1,
+ gsub_reversecontextchain=-1, + gpos_reversecontextchain=-1, } -local function supported(features)
- for i=1,#features do
- if features[i].ismac then
- return false
- end
- end
- return true
-end -actions["reorganize subtables"]=function(data,filename,raw)
- local resources=data.resources
- local sequences={}
- local lookups={}
- local chainedfeatures={}
- resources.sequences=sequences
- resources.lookups=lookups
- for _,what in next,otf.glists do
- local dw=raw[what]
- if dw then
- for k=1,#dw do
- local gk=dw[k]
+local function supported(features) + for i=1,#features do + if features[i].ismac then + return false + end + end + return true +end +actions["reorganize subtables"]=function(data,filename,raw) + local resources=data.resources + local sequences={} + local lookups={} + local chainedfeatures={} + resources.sequences=sequences + resources.lookups=lookups + for _,what in next,otf.glists do + local dw=raw[what] + if dw then + for k=1,#dw do + local gk=dw[k] local features=gk.features if not features or supported(features) then - local typ=gk.type
- local chain=g_directions[typ] or 0
- local subtables=gk.subtables
- if subtables then
- local t={}
- for s=1,#subtables do
- t[s]=subtables[s].name
- end
- subtables=t
- end
- local flags,markclass=gk.flags,nil
- if flags then
+ local typ=gk.type + local chain=g_directions[typ] or 0 + local subtables=gk.subtables + if subtables then + local t={} + for s=1,#subtables do + t[s]=subtables[s].name + end + subtables=t + end + local flags,markclass=gk.flags,nil + if flags then local t={ - (flags.ignorecombiningmarks and "mark") or false,
- (flags.ignoreligatures and "ligature") or false,
- (flags.ignorebaseglyphs and "base") or false,
- flags.r2l or false,
- }
- markclass=flags.mark_class
- if markclass then
- markclass=resources.markclasses[markclass]
- end
- flags=t
+ (flags.ignorecombiningmarks and "mark") or false, + (flags.ignoreligatures and "ligature") or false, + (flags.ignorebaseglyphs and "base") or false, + flags.r2l or false, + } + markclass=flags.mark_class + if markclass then + markclass=resources.markclasses[markclass] + end + flags=t end local name=gk.name if not name then - report_otf("skipping weird lookup number %s",k)
+ report_otf("skipping weird lookup number %s",k) elseif features then - local f={}
- for i=1,#features do
- local df=features[i]
- local tag=strip(lower(df.tag))
- local ft=f[tag] if not ft then ft={} f[tag]=ft end
- local dscripts=df.scripts
- for i=1,#dscripts do
- local d=dscripts[i]
- local languages=d.langs
- local script=strip(lower(d.script))
- local fts=ft[script] if not fts then fts={} ft[script]=fts end
- for i=1,#languages do
- fts[strip(lower(languages[i]))]=true
- end
- end
- end
- sequences[#sequences+1]={
- type=typ,
- chain=chain,
- flags=flags,
- name=name,
- subtables=subtables,
- markclass=markclass,
- features=f,
- }
- else
- lookups[name]={
- type=typ,
- chain=chain,
- flags=flags,
- subtables=subtables,
- markclass=markclass,
- }
- end
- end
- end
- end
- end
-end -actions["prepare lookups"]=function(data,filename,raw)
- local lookups=raw.lookups
- if lookups then
- data.lookups=lookups
- end
-end -local function t_uncover(splitter,cache,covers)
- local result={}
- for n=1,#covers do
- local cover=covers[n]
- local uncovered=cache[cover]
- if not uncovered then
- uncovered=lpegmatch(splitter,cover)
- cache[cover]=uncovered
- end
- result[n]=uncovered
- end
- return result
-end -local function s_uncover(splitter,cache,cover)
- if cover=="" then
- return nil
- else
- local uncovered=cache[cover]
- if not uncovered then
+ local f={} + for i=1,#features do + local df=features[i] + local tag=strip(lower(df.tag)) + local ft=f[tag] if not ft then ft={} f[tag]=ft end + local dscripts=df.scripts + for i=1,#dscripts do + local d=dscripts[i] + local languages=d.langs + local script=strip(lower(d.script)) + local fts=ft[script] if not fts then fts={} ft[script]=fts end + for i=1,#languages do + fts[strip(lower(languages[i]))]=true + end + end + end + sequences[#sequences+1]={ + type=typ, + chain=chain, + flags=flags, + name=name, + subtables=subtables, + markclass=markclass, + features=f, + } + else + lookups[name]={ + type=typ, + chain=chain, + flags=flags, + subtables=subtables, + markclass=markclass, + } + end + end + end + end + end +end +actions["prepare lookups"]=function(data,filename,raw) + local lookups=raw.lookups + if lookups then + data.lookups=lookups + end +end +local function t_uncover(splitter,cache,covers) + local result={} + for n=1,#covers do + local cover=covers[n] + local uncovered=cache[cover] + if not uncovered then uncovered=lpegmatch(splitter,cover) - cache[cover]=uncovered
- end
- return { uncovered }
- end
-end -local function t_hashed(t,cache)
- if t then
- local ht={}
- for i=1,#t do
- local ti=t[i]
- local tih=cache[ti]
- if not tih then
- tih={}
- for i=1,#ti do
- tih[ti[i]]=true
- end
- cache[ti]=tih
- end
- ht[i]=tih
- end
- return ht
- else
- return nil
- end
-end -local function s_hashed(t,cache)
- if t then
- local ht={}
- local tf=t[1]
- for i=1,#tf do
- ht[i]={ [tf[i]]=true }
- end
- return ht
- else
- return nil
- end
-end -local function r_uncover(splitter,cache,cover,replacements)
- if cover=="" then
- return nil
+ cache[cover]=uncovered + end + result[n]=uncovered + end + return result +end +local function s_uncover(splitter,cache,cover) + if cover=="" then + return nil else - local uncovered=cover[1]
- local replaced=cache[replacements]
- if not replaced then
- replaced=lpegmatch(splitter,replacements)
- cache[replacements]=replaced
- end
- local nu,nr=#uncovered,#replaced
- local r={}
- if nu==nr then
- for i=1,nu do
- r[uncovered[i]]=replaced[i]
- end
- end
- return r
- end
+ local uncovered=cache[cover] + if not uncovered then + uncovered=lpegmatch(splitter,cover) + cache[cover]=uncovered + end + return { uncovered } + end +end +local function t_hashed(t,cache) + if t then + local ht={} + for i=1,#t do + local ti=t[i] + local tih=cache[ti] + if not tih then + tih={} + for i=1,#ti do + tih[ti[i]]=true + end + cache[ti]=tih + end + ht[i]=tih + end + return ht + else + return nil + end +end +local function s_hashed(t,cache) + if t then + local ht={} + local tf=t[1] + for i=1,#tf do + ht[i]={ [tf[i]]=true } + end + return ht + else + return nil + end +end +local function r_uncover(splitter,cache,cover,replacements) + if cover=="" then + return nil + else + local uncovered=cover[1] + local replaced=cache[replacements] + if not replaced then + replaced=lpegmatch(splitter,replacements) + cache[replacements]=replaced + end + local nu,nr=#uncovered,#replaced + local r={} + if nu==nr then + for i=1,nu do + r[uncovered[i]]=replaced[i] + end + end + return r + end end actions["reorganize lookups"]=function(data,filename,raw) - if data.lookups then
- local splitter=data.helpers.tounicodetable
- local t_u_cache={}
+ if data.lookups then + local splitter=data.helpers.tounicodetable + local t_u_cache={} local s_u_cache=t_u_cache - local t_h_cache={}
+ local t_h_cache={} local s_h_cache=t_h_cache local r_u_cache={} - for _,lookup in next,data.lookups do
- local rules=lookup.rules
- if rules then
- local format=lookup.format
- if format=="class" then
- local before_class=lookup.before_class
- if before_class then
- before_class=t_uncover(splitter,t_u_cache,reversed(before_class))
- end
- local current_class=lookup.current_class
- if current_class then
- current_class=t_uncover(splitter,t_u_cache,current_class)
- end
- local after_class=lookup.after_class
- if after_class then
- after_class=t_uncover(splitter,t_u_cache,after_class)
- end
- for i=1,#rules do
- local rule=rules[i]
- local class=rule.class
- local before=class.before
- if before then
- for i=1,#before do
- before[i]=before_class[before[i]] or {}
- end
- rule.before=t_hashed(before,t_h_cache)
- end
- local current=class.current
- local lookups=rule.lookups
- if current then
- for i=1,#current do
+ for _,lookup in next,data.lookups do + local rules=lookup.rules + if rules then + local format=lookup.format + if format=="class" then + local before_class=lookup.before_class + if before_class then + before_class=t_uncover(splitter,t_u_cache,reversed(before_class)) + end + local current_class=lookup.current_class + if current_class then + current_class=t_uncover(splitter,t_u_cache,current_class) + end + local after_class=lookup.after_class + if after_class then + after_class=t_uncover(splitter,t_u_cache,after_class) + end + for i=1,#rules do + local rule=rules[i] + local class=rule.class + local before=class.before + if before then + for i=1,#before do + before[i]=before_class[before[i]] or {} + end + rule.before=t_hashed(before,t_h_cache) + end + local current=class.current + local lookups=rule.lookups + if current then + for i=1,#current do current[i]=current_class[current[i]] or {} - if lookups and not lookups[i] then
+ if lookups and not lookups[i] then lookups[i]="" end - end
- rule.current=t_hashed(current,t_h_cache)
- end
- local after=class.after
- if after then
- for i=1,#after do
- after[i]=after_class[after[i]] or {}
- end
- rule.after=t_hashed(after,t_h_cache)
- end
- rule.class=nil
- end
- lookup.before_class=nil
- lookup.current_class=nil
- lookup.after_class=nil
- lookup.format="coverage"
- elseif format=="coverage" then
- for i=1,#rules do
- local rule=rules[i]
- local coverage=rule.coverage
- if coverage then
- local before=coverage.before
- if before then
- before=t_uncover(splitter,t_u_cache,reversed(before))
- rule.before=t_hashed(before,t_h_cache)
- end
- local current=coverage.current
- if current then
+ end + rule.current=t_hashed(current,t_h_cache) + end + local after=class.after + if after then + for i=1,#after do + after[i]=after_class[after[i]] or {} + end + rule.after=t_hashed(after,t_h_cache) + end + rule.class=nil + end + lookup.before_class=nil + lookup.current_class=nil + lookup.after_class=nil + lookup.format="coverage" + elseif format=="coverage" then + for i=1,#rules do + local rule=rules[i] + local coverage=rule.coverage + if coverage then + local before=coverage.before + if before then + before=t_uncover(splitter,t_u_cache,reversed(before)) + rule.before=t_hashed(before,t_h_cache) + end + local current=coverage.current + if current then current=t_uncover(splitter,t_u_cache,current) - local lookups=rule.lookups
- if lookups then
- for i=1,#current do
- if not lookups[i] then
+ local lookups=rule.lookups + if lookups then + for i=1,#current do + if not lookups[i] then lookups[i]="" - end
- end
+ end + end end - rule.current=t_hashed(current,t_h_cache)
- end
- local after=coverage.after
- if after then
- after=t_uncover(splitter,t_u_cache,after)
- rule.after=t_hashed(after,t_h_cache)
- end
- rule.coverage=nil
- end
- end
+ rule.current=t_hashed(current,t_h_cache) + end + local after=coverage.after + if after then + after=t_uncover(splitter,t_u_cache,after) + rule.after=t_hashed(after,t_h_cache) + end + rule.coverage=nil + end + end elseif format=="reversecoverage" then - for i=1,#rules do
- local rule=rules[i]
- local reversecoverage=rule.reversecoverage
- if reversecoverage then
- local before=reversecoverage.before
- if before then
- before=t_uncover(splitter,t_u_cache,reversed(before))
- rule.before=t_hashed(before,t_h_cache)
- end
- local current=reversecoverage.current
- if current then
- current=t_uncover(splitter,t_u_cache,current)
- rule.current=t_hashed(current,t_h_cache)
- end
- local after=reversecoverage.after
- if after then
- after=t_uncover(splitter,t_u_cache,after)
- rule.after=t_hashed(after,t_h_cache)
- end
- local replacements=reversecoverage.replacements
- if replacements then
- rule.replacements=r_uncover(splitter,r_u_cache,current,replacements)
- end
- rule.reversecoverage=nil
- end
- end
+ for i=1,#rules do + local rule=rules[i] + local reversecoverage=rule.reversecoverage + if reversecoverage then + local before=reversecoverage.before + if before then + before=t_uncover(splitter,t_u_cache,reversed(before)) + rule.before=t_hashed(before,t_h_cache) + end + local current=reversecoverage.current + if current then + current=t_uncover(splitter,t_u_cache,current) + rule.current=t_hashed(current,t_h_cache) + end + local after=reversecoverage.after + if after then + after=t_uncover(splitter,t_u_cache,after) + rule.after=t_hashed(after,t_h_cache) + end + local replacements=reversecoverage.replacements + if replacements then + rule.replacements=r_uncover(splitter,r_u_cache,current,replacements) + end + rule.reversecoverage=nil + end + end elseif format=="glyphs" then - for i=1,#rules do
- local rule=rules[i]
- local glyphs=rule.glyphs
- if glyphs then
- local fore=glyphs.fore
- if fore and fore~="" then
- fore=s_uncover(splitter,s_u_cache,fore)
- rule.before=s_hashed(fore,s_h_cache)
- end
- local back=glyphs.back
- if back then
- back=s_uncover(splitter,s_u_cache,back)
- rule.after=s_hashed(back,s_h_cache)
- end
- local names=glyphs.names
- if names then
- names=s_uncover(splitter,s_u_cache,names)
- rule.current=s_hashed(names,s_h_cache)
- end
- rule.glyphs=nil
- end
- end
- end
- end
- end
- end
-end -local function check_variants(unicode,the_variants,splitter,unicodes)
- local variants=the_variants.variants
+ for i=1,#rules do + local rule=rules[i] + local glyphs=rule.glyphs + if glyphs then + local fore=glyphs.fore + if fore and fore~="" then + fore=s_uncover(splitter,s_u_cache,fore) + rule.before=s_hashed(fore,s_h_cache) + end + local back=glyphs.back + if back then + back=s_uncover(splitter,s_u_cache,back) + rule.after=s_hashed(back,s_h_cache) + end + local names=glyphs.names + if names then + names=s_uncover(splitter,s_u_cache,names) + rule.current=s_hashed(names,s_h_cache) + end + rule.glyphs=nil + end + end + end + end + end + end +end +local function check_variants(unicode,the_variants,splitter,unicodes) + local variants=the_variants.variants if variants then - local glyphs=lpegmatch(splitter,variants)
- local done={ [unicode]=true }
- local n=0
- for i=1,#glyphs do
- local g=glyphs[i]
- if done[g] then
- report_otf("skipping cyclic reference %U in math variant %U",g,unicode)
- else
- if n==0 then
- n=1
- variants={ g }
- else
- n=n+1
- variants[n]=g
- end
- done[g]=true
- end
- end
- if n==0 then
- variants=nil
- end
- end
- local parts=the_variants.parts
- if parts then
- local p=#parts
- if p>0 then
- for i=1,p do
- local pi=parts[i]
- pi.glyph=unicodes[pi.component] or 0
- pi.component=nil
- end
- else
- parts=nil
- end
- end
- local italic_correction=the_variants.italic_correction
- if italic_correction and italic_correction==0 then
- italic_correction=nil
- end
- return variants,parts,italic_correction
-end -actions["analyze math"]=function(data,filename,raw)
- if raw.math then
- data.metadata.math=raw.math
- local unicodes=data.resources.unicodes
- local splitter=data.helpers.tounicodetable
- for unicode,description in next,data.descriptions do
- local glyph=description.glyph
+ local glyphs=lpegmatch(splitter,variants) + local done={ [unicode]=true } + local n=0 + for i=1,#glyphs do + local g=glyphs[i] + if done[g] then + report_otf("skipping cyclic reference %U in math variant %U",g,unicode) + else + if n==0 then + n=1 + variants={ g } + else + n=n+1 + variants[n]=g + end + done[g]=true + end + end + if n==0 then + variants=nil + end + end + local parts=the_variants.parts + if parts then + local p=#parts + if p>0 then + for i=1,p do + local pi=parts[i] + pi.glyph=unicodes[pi.component] or 0 + pi.component=nil + end + else + parts=nil + end + end + local italic_correction=the_variants.italic_correction + if italic_correction and italic_correction==0 then + italic_correction=nil + end + return variants,parts,italic_correction +end +actions["analyze math"]=function(data,filename,raw) + if raw.math then + data.metadata.math=raw.math + local unicodes=data.resources.unicodes + local splitter=data.helpers.tounicodetable + for unicode,description in next,data.descriptions do + local glyph=description.glyph local mathkerns=glyph.mathkern - local horiz_variants=glyph.horiz_variants
- local vert_variants=glyph.vert_variants
- local top_accent=glyph.top_accent
- if mathkerns or horiz_variants or vert_variants or top_accent then
- local math={}
- if top_accent then
- math.top_accent=top_accent
- end
- if mathkerns then
- for k,v in next,mathkerns do
- if not next(v) then
- mathkerns[k]=nil
- else
- for k,v in next,v do
- if v==0 then
+ local horiz_variants=glyph.horiz_variants + local vert_variants=glyph.vert_variants + local top_accent=glyph.top_accent + if mathkerns or horiz_variants or vert_variants or top_accent then + local math={} + if top_accent then + math.top_accent=top_accent + end + if mathkerns then + for k,v in next,mathkerns do + if not next(v) then + mathkerns[k]=nil + else + for k,v in next,v do + if v==0 then k[v]=nil - end
- end
- end
- end
- math.kerns=mathkerns
- end
- if horiz_variants then
- math.horiz_variants,math.horiz_parts,math.horiz_italic_correction=check_variants(unicode,horiz_variants,splitter,unicodes)
- end
- if vert_variants then
- math.vert_variants,math.vert_parts,math.vert_italic_correction=check_variants(unicode,vert_variants,splitter,unicodes)
- end
- local italic_correction=description.italic
- if italic_correction and italic_correction~=0 then
- math.italic_correction=italic_correction
- end
- description.math=math
- end
- end
- end
-end -actions["reorganize glyph kerns"]=function(data,filename,raw)
- local descriptions=data.descriptions
- local resources=data.resources
- local unicodes=resources.unicodes
- for unicode,description in next,descriptions do
- local kerns=description.glyph.kerns
- if kerns then
- local newkerns={}
- for k,kern in next,kerns do
- local name=kern.char
- local offset=kern.off
- local lookup=kern.lookup
- if name and offset and lookup then
- local unicode=unicodes[name]
- if unicode then
- if type(lookup)=="table" then
- for l=1,#lookup do
- local lookup=lookup[l]
- local lookupkerns=newkerns[lookup]
- if lookupkerns then
- lookupkerns[unicode]=offset
- else
- newkerns[lookup]={ [unicode]=offset }
- end
- end
- else
- local lookupkerns=newkerns[lookup]
- if lookupkerns then
- lookupkerns[unicode]=offset
- else
- newkerns[lookup]={ [unicode]=offset }
- end
- end
- elseif trace_loading then
- report_otf("problems with unicode %a of kern %a of glyph %U",name,k,unicode)
- end
- end
- end
- description.kerns=newkerns
- end
- end
-end -actions["merge kern classes"]=function(data,filename,raw)
- local gposlist=raw.gpos
- if gposlist then
- local descriptions=data.descriptions
- local resources=data.resources
- local unicodes=resources.unicodes
- local splitter=data.helpers.tounicodetable
- for gp=1,#gposlist do
- local gpos=gposlist[gp]
- local subtables=gpos.subtables
- if subtables then
- for s=1,#subtables do
- local subtable=subtables[s]
+ end + end + end + end + math.kerns=mathkerns + end + if horiz_variants then + math.horiz_variants,math.horiz_parts,math.horiz_italic_correction=check_variants(unicode,horiz_variants,splitter,unicodes) + end + if vert_variants then + math.vert_variants,math.vert_parts,math.vert_italic_correction=check_variants(unicode,vert_variants,splitter,unicodes) + end + local italic_correction=description.italic + if italic_correction and italic_correction~=0 then + math.italic_correction=italic_correction + end + description.math=math + end + end + end +end +actions["reorganize glyph kerns"]=function(data,filename,raw) + local descriptions=data.descriptions + local resources=data.resources + local unicodes=resources.unicodes + for unicode,description in next,descriptions do + local kerns=description.glyph.kerns + if kerns then + local newkerns={} + for k,kern in next,kerns do + local name=kern.char + local offset=kern.off + local lookup=kern.lookup + if name and offset and lookup then + local unicode=unicodes[name] + if unicode then + if type(lookup)=="table" then + for l=1,#lookup do + local lookup=lookup[l] + local lookupkerns=newkerns[lookup] + if lookupkerns then + lookupkerns[unicode]=offset + else + newkerns[lookup]={ [unicode]=offset } + end + end + else + local lookupkerns=newkerns[lookup] + if lookupkerns then + lookupkerns[unicode]=offset + else + newkerns[lookup]={ [unicode]=offset } + end + end + elseif trace_loading then + report_otf("problems with unicode %a of kern %a of glyph %U",name,k,unicode) + end + end + end + description.kerns=newkerns + end + end +end +actions["merge kern classes"]=function(data,filename,raw) + local gposlist=raw.gpos + if gposlist then + local descriptions=data.descriptions + local resources=data.resources + local unicodes=resources.unicodes + local splitter=data.helpers.tounicodetable + for gp=1,#gposlist do + local gpos=gposlist[gp] + local subtables=gpos.subtables + if subtables then + for s=1,#subtables do + local subtable=subtables[s] local kernclass=subtable.kernclass if kernclass then local split={} - for k=1,#kernclass do
- local kcl=kernclass[k]
- local firsts=kcl.firsts
- local seconds=kcl.seconds
- local offsets=kcl.offsets
+ for k=1,#kernclass do + local kcl=kernclass[k] + local firsts=kcl.firsts + local seconds=kcl.seconds + local offsets=kcl.offsets local lookups=kcl.lookup - if type(lookups)~="table" then
- lookups={ lookups }
+ if type(lookups)~="table" then + lookups={ lookups } + end + for n,s in next,firsts do + split[s]=split[s] or lpegmatch(splitter,s) end - for n,s in next,firsts do
- split[s]=split[s] or lpegmatch(splitter,s)
- end
- local maxseconds=0
- for n,s in next,seconds do
- if n>maxseconds then
- maxseconds=n
- end
- split[s]=split[s] or lpegmatch(splitter,s)
- end
- for l=1,#lookups do
- local lookup=lookups[l]
+ local maxseconds=0 + for n,s in next,seconds do + if n>maxseconds then + maxseconds=n + end + split[s]=split[s] or lpegmatch(splitter,s) + end + for l=1,#lookups do + local lookup=lookups[l] for fk=1,#firsts do - local fv=firsts[fk]
- local splt=split[fv]
- if splt then
- local extrakerns={}
- local baseoffset=(fk-1)*maxseconds
+ local fv=firsts[fk] + local splt=split[fv] + if splt then + local extrakerns={} + local baseoffset=(fk-1)*maxseconds for sk=2,maxseconds do local sv=seconds[sk] - local splt=split[sv]
+ local splt=split[sv] if splt then - local offset=offsets[baseoffset+sk]
- if offset then
- for i=1,#splt do
- extrakerns[splt[i]]=offset
- end
- end
- end
- end
- for i=1,#splt do
- local first_unicode=splt[i]
- local description=descriptions[first_unicode]
- if description then
- local kerns=description.kerns
- if not kerns then
+ local offset=offsets[baseoffset+sk] + if offset then + for i=1,#splt do + extrakerns[splt[i]]=offset + end + end + end + end + for i=1,#splt do + local first_unicode=splt[i] + local description=descriptions[first_unicode] + if description then + local kerns=description.kerns + if not kerns then kerns={} - description.kerns=kerns
- end
- local lookupkerns=kerns[lookup]
- if not lookupkerns then
- lookupkerns={}
- kerns[lookup]=lookupkerns
- end
- for second_unicode,kern in next,extrakerns do
- lookupkerns[second_unicode]=kern
- end
- elseif trace_loading then
- report_otf("no glyph data for %U",first_unicode)
- end
- end
- end
- end
- end
- end
- subtable.kernclass={}
- end
- end
- end
- end
- end
-end -actions["check glyphs"]=function(data,filename,raw)
- for unicode,description in next,data.descriptions do
- description.glyph=nil
- end
-end -actions["check metadata"]=function(data,filename,raw)
- local metadata=data.metadata
- for _,k in next,mainfields do
- if valid_fields[k] then
- local v=raw[k]
- if not metadata[k] then
- metadata[k]=v
- end
- end
- end - local ttftables=metadata.ttf_tables
- if ttftables then
- for i=1,#ttftables do
- ttftables[i].data="deleted"
- end
- end
-end -actions["cleanup tables"]=function(data,filename,raw)
+ description.kerns=kerns + end + local lookupkerns=kerns[lookup] + if not lookupkerns then + lookupkerns={} + kerns[lookup]=lookupkerns + end + for second_unicode,kern in next,extrakerns do + lookupkerns[second_unicode]=kern + end + elseif trace_loading then + report_otf("no glyph data for %U",first_unicode) + end + end + end + end + end + end + subtable.kernclass={} + end + end + end + end + end +end +actions["check glyphs"]=function(data,filename,raw) + for unicode,description in next,data.descriptions do + description.glyph=nil + end +end +actions["check metadata"]=function(data,filename,raw) + local metadata=data.metadata + for _,k in next,mainfields do + if valid_fields[k] then + local v=raw[k] + if not metadata[k] then + metadata[k]=v + end + end + end + local ttftables=metadata.ttf_tables + if ttftables then + for i=1,#ttftables do + ttftables[i].data="deleted" + end + end +end +actions["cleanup tables"]=function(data,filename,raw) data.resources.indices=nil - data.helpers=nil
+ data.helpers=nil end -actions["reorganize glyph lookups"]=function(data,filename,raw)
- local resources=data.resources
- local unicodes=resources.unicodes
- local descriptions=data.descriptions
+actions["reorganize glyph lookups"]=function(data,filename,raw) + local resources=data.resources + local unicodes=resources.unicodes + local descriptions=data.descriptions local splitter=data.helpers.tounicodelist local lookuptypes=resources.lookuptypes - for unicode,description in next,descriptions do
- local lookups=description.glyph.lookups
- if lookups then
- for tag,lookuplist in next,lookups do
- for l=1,#lookuplist do
- local lookup=lookuplist[l]
- local specification=lookup.specification
- local lookuptype=lookup.type
- local lt=lookuptypes[tag]
- if not lt then
- lookuptypes[tag]=lookuptype
- elseif lt~=lookuptype then
- report_otf("conflicting lookuptypes, %a points to %a and %a",tag,lt,lookuptype)
- end
- if lookuptype=="ligature" then
- lookuplist[l]={ lpegmatch(splitter,specification.components) }
- elseif lookuptype=="alternate" then
- lookuplist[l]={ lpegmatch(splitter,specification.components) }
- elseif lookuptype=="substitution" then
- lookuplist[l]=unicodes[specification.variant]
- elseif lookuptype=="multiple" then
- lookuplist[l]={ lpegmatch(splitter,specification.components) }
- elseif lookuptype=="position" then
- lookuplist[l]={
- specification.x or 0,
- specification.y or 0,
- specification.h or 0,
- specification.v or 0
- }
- elseif lookuptype=="pair" then
- local one=specification.offsets[1]
- local two=specification.offsets[2]
- local paired=unicodes[specification.paired]
- if one then
- if two then
- lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 },{ two.x or 0,two.y or 0,two.h or 0,two.v or 0 } }
- else
- lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 } }
- end
- else
- if two then
+ for unicode,description in next,descriptions do + local lookups=description.glyph.lookups + if lookups then + for tag,lookuplist in next,lookups do + for l=1,#lookuplist do + local lookup=lookuplist[l] + local specification=lookup.specification + local lookuptype=lookup.type + local lt=lookuptypes[tag] + if not lt then + lookuptypes[tag]=lookuptype + elseif lt~=lookuptype then + report_otf("conflicting lookuptypes, %a points to %a and %a",tag,lt,lookuptype) + end + if lookuptype=="ligature" then + lookuplist[l]={ lpegmatch(splitter,specification.components) } + elseif lookuptype=="alternate" then + lookuplist[l]={ lpegmatch(splitter,specification.components) } + elseif lookuptype=="substitution" then + lookuplist[l]=unicodes[specification.variant] + elseif lookuptype=="multiple" then + lookuplist[l]={ lpegmatch(splitter,specification.components) } + elseif lookuptype=="position" then + lookuplist[l]={ + specification.x or 0, + specification.y or 0, + specification.h or 0, + specification.v or 0 + } + elseif lookuptype=="pair" then + local one=specification.offsets[1] + local two=specification.offsets[2] + local paired=unicodes[specification.paired] + if one then + if two then + lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 },{ two.x or 0,two.y or 0,two.h or 0,two.v or 0 } } + else + lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 } } + end + else + if two then lookuplist[l]={ paired,{},{ two.x or 0,two.y or 0,two.h or 0,two.v or 0} } - else
- lookuplist[l]={ paired }
- end
- end
- end
- end
- end
- local slookups,mlookups
- for tag,lookuplist in next,lookups do
- if #lookuplist==1 then
- if slookups then
- slookups[tag]=lookuplist[1]
- else
- slookups={ [tag]=lookuplist[1] }
- end
- else
- if mlookups then
- mlookups[tag]=lookuplist
- else
- mlookups={ [tag]=lookuplist }
- end
- end
- end
- if slookups then
- description.slookups=slookups
- end
- if mlookups then
- description.mlookups=mlookups
- end
- end
+ else + lookuplist[l]={ paired } + end + end + end + end + end + local slookups,mlookups + for tag,lookuplist in next,lookups do + if #lookuplist==1 then + if slookups then + slookups[tag]=lookuplist[1] + else + slookups={ [tag]=lookuplist[1] } + end + else + if mlookups then + mlookups[tag]=lookuplist + else + mlookups={ [tag]=lookuplist } + end + end + end + if slookups then + description.slookups=slookups + end + if mlookups then + description.mlookups=mlookups + end + end end end actions["reorganize glyph anchors"]=function(data,filename,raw) - local descriptions=data.descriptions
- for unicode,description in next,descriptions do
- local anchors=description.glyph.anchors
- if anchors then
- for class,data in next,anchors do
- if class=="baselig" then
- for tag,specification in next,data do
- for i=1,#specification do
- local si=specification[i]
- specification[i]={ si.x or 0,si.y or 0 }
- end
- end
- else
- for tag,specification in next,data do
- data[tag]={ specification.x or 0,specification.y or 0 }
- end
- end
- end
- description.anchors=anchors
- end
- end
-end -function otf.setfeatures(tfmdata,features)
- local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf)
- if okay then
- return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf)
- else
+ local descriptions=data.descriptions + for unicode,description in next,descriptions do + local anchors=description.glyph.anchors + if anchors then + for class,data in next,anchors do + if class=="baselig" then + for tag,specification in next,data do + for i=1,#specification do + local si=specification[i] + specification[i]={ si.x or 0,si.y or 0 } + end + end + else + for tag,specification in next,data do + data[tag]={ specification.x or 0,specification.y or 0 } + end + end + end + description.anchors=anchors + end + end +end +function otf.setfeatures(tfmdata,features) + local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf) + if okay then + return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf) + else return {} - end
-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)
- local characters={}
- local parameters={}
+ end +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) + local characters={} + local parameters={} local mathparameters={} - local pfminfo=metadata.pfminfo or {}
- local resources=data.resources
+ local pfminfo=metadata.pfminfo or {} + local resources=data.resources local unicodes=resources.unicodes - local spaceunits=500
- local spacer="space"
- local designsize=metadata.designsize or metadata.design_size or 100
+ local spaceunits=500 + local spacer="space" + local designsize=metadata.designsize or metadata.design_size or 100 local mathspecs=metadata.math - if designsize==0 then
- designsize=100
- end
- if mathspecs then
- for name,value in next,mathspecs do
- mathparameters[name]=value
- end
- end
+ if designsize==0 then + designsize=100 + end + if mathspecs then + for name,value in next,mathspecs do + mathparameters[name]=value + end + end for unicode,_ in next,data.descriptions do - characters[unicode]={}
- end
+ characters[unicode]={} + end if mathspecs then - for unicode,character in next,characters do
- local d=descriptions[unicode]
- local m=d.math
+ for unicode,character in next,characters do + local d=descriptions[unicode] + local m=d.math if m then - local variants=m.horiz_variants
+ local variants=m.horiz_variants local parts=m.horiz_parts - if variants then
- local c=character
- for i=1,#variants do
+ if variants then + local c=character + for i=1,#variants do local un=variants[i] - c.next=un
+ c.next=un c=characters[un] end - c.horiz_variants=parts
- elseif parts then
- character.horiz_variants=parts
- end
- local variants=m.vert_variants
+ c.horiz_variants=parts + elseif parts then + character.horiz_variants=parts + end + local variants=m.vert_variants local parts=m.vert_parts - if variants then
- local c=character
- for i=1,#variants do
+ if variants then + local c=character + for i=1,#variants do local un=variants[i] - c.next=un
+ c.next=un c=characters[un] end - c.vert_variants=parts
- elseif parts then
- character.vert_variants=parts
- end
- local italic_correction=m.vert_italic_correction
- if italic_correction then
+ c.vert_variants=parts + elseif parts then + character.vert_variants=parts + end + local italic_correction=m.vert_italic_correction + if italic_correction then character.vert_italic_correction=italic_correction - end
- local top_accent=m.top_accent
- if top_accent then
- character.top_accent=top_accent
- end
- local kerns=m.kerns
- if kerns then
- character.mathkerns=kerns
- end
- end
- end
- end - local monospaced=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced")
+ end + local top_accent=m.top_accent + if top_accent then + character.top_accent=top_accent + end + local kerns=m.kerns + if kerns then + character.mathkerns=kerns + end + end + end + end + local monospaced=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced") local charwidth=pfminfo.avgwidth - local italicangle=metadata.italicangle
- local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight
- properties.monospaced=monospaced
- parameters.italicangle=italicangle
- parameters.charwidth=charwidth
+ local italicangle=metadata.italicangle + local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight + properties.monospaced=monospaced + parameters.italicangle=italicangle + parameters.charwidth=charwidth parameters.charxheight=charxheight local space=0x0020 local emdash=0x2014 - if monospaced then
- if descriptions[space] then
- spaceunits,spacer=descriptions[space].width,"space"
- end
- if not spaceunits and descriptions[emdash] then
- spaceunits,spacer=descriptions[emdash].width,"emdash"
- end
- if not spaceunits and charwidth then
- spaceunits,spacer=charwidth,"charwidth"
- end
- else
- if descriptions[space] then
- spaceunits,spacer=descriptions[space].width,"space"
- end
- if not spaceunits and descriptions[emdash] then
- spaceunits,spacer=descriptions[emdash].width/2,"emdash/2"
- end
- if not spaceunits and charwidth then
- spaceunits,spacer=charwidth,"charwidth"
- end
- end
+ if monospaced then + if descriptions[space] then + spaceunits,spacer=descriptions[space].width,"space" + end + if not spaceunits and descriptions[emdash] then + spaceunits,spacer=descriptions[emdash].width,"emdash" + end + if not spaceunits and charwidth then + spaceunits,spacer=charwidth,"charwidth" + end + else + if descriptions[space] then + spaceunits,spacer=descriptions[space].width,"space" + end + if not spaceunits and descriptions[emdash] then + spaceunits,spacer=descriptions[emdash].width/2,"emdash/2" + end + if not spaceunits and charwidth then + spaceunits,spacer=charwidth,"charwidth" + end + end spaceunits=tonumber(spaceunits) or 500 - local filename=constructors.checkedfilename(resources)
- local fontname=metadata.fontname
- local fullname=metadata.fullname or fontname
+ local filename=constructors.checkedfilename(resources) + local fontname=metadata.fontname + local fullname=metadata.fullname or fontname local units=metadata.units_per_em or 1000 if units==0 then - units=1000
- metadata.units_per_em=1000
+ units=1000 + metadata.units_per_em=1000 end - parameters.slant=0
+ parameters.slant=0 parameters.space=spaceunits parameters.space_stretch=units/2 parameters.space_shrink=1*units/3 parameters.x_height=2*units/5 parameters.quad=units if spaceunits<2*units/5 then - end
- if italicangle then
- parameters.italicangle=italicangle
- parameters.italicfactor=math.cos(math.rad(90+italicangle))
- parameters.slant=- math.round(math.tan(italicangle*math.pi/180))
- end
- if monospaced then
- parameters.space_stretch=0
- parameters.space_shrink=0
+ end + if italicangle then + parameters.italicangle=italicangle + parameters.italicfactor=math.cos(math.rad(90+italicangle)) + parameters.slant=- math.round(math.tan(italicangle*math.pi/180)) + end + if monospaced then + parameters.space_stretch=0 + parameters.space_shrink=0 elseif syncspace then - parameters.space_stretch=spaceunits/2
- parameters.space_shrink=spaceunits/3
- end
+ parameters.space_stretch=spaceunits/2 + parameters.space_shrink=spaceunits/3 + end parameters.extra_space=parameters.space_shrink - if charxheight then
- parameters.x_height=charxheight
- else
+ if charxheight then + parameters.x_height=charxheight + else local x=0x78 - if x then
- local x=descriptions[x]
- if x then
- parameters.x_height=x.height
- end
- end
- end - parameters.designsize=(designsize/10)*65536
- parameters.ascender=abs(metadata.ascent or 0)
- parameters.descender=abs(metadata.descent or 0)
+ if x then + local x=descriptions[x] + if x then + parameters.x_height=x.height + end + end + end + parameters.designsize=(designsize/10)*65536 + parameters.ascender=abs(metadata.ascent or 0) + parameters.descender=abs(metadata.descent or 0) parameters.units=units - properties.space=spacer
- properties.encodingbytes=2
- properties.format=data.format or fonts.formats[filename] or "opentype"
- properties.noglyphnames=true
- properties.filename=filename
- properties.fontname=fontname
- properties.fullname=fullname
- properties.psname=fontname or fullname
+ properties.space=spacer + properties.encodingbytes=2 + properties.format=data.format or fonts.formats[filename] or "opentype" + properties.noglyphnames=true + properties.filename=filename + properties.fontname=fontname + properties.fullname=fullname + properties.psname=fontname or fullname properties.name=filename or fullname - return {
- characters=characters,
- descriptions=descriptions,
- parameters=parameters,
- mathparameters=mathparameters,
- resources=resources,
- properties=properties,
- goodies=goodies,
- }
- end
-end -local function otftotfm(specification)
- local cache_id=specification.hash
- local tfmdata=containers.read(constructors.cache,cache_id)
- if not tfmdata then
- local name=specification.name
- local sub=specification.sub
- local filename=specification.filename
- local format=specification.format
- local features=specification.features.normal
- local rawdata=otf.load(filename,format,sub,features and features.featurefile)
- if rawdata and next(rawdata) then
- rawdata.lookuphash={}
- tfmdata=copytotfm(rawdata,cache_id)
+ return { + characters=characters, + descriptions=descriptions, + parameters=parameters, + mathparameters=mathparameters, + resources=resources, + properties=properties, + goodies=goodies, + } + end +end +local function otftotfm(specification) + local cache_id=specification.hash + local tfmdata=containers.read(constructors.cache,cache_id) + if not tfmdata then + local name=specification.name + local sub=specification.sub + local filename=specification.filename + local format=specification.format + local features=specification.features.normal + local rawdata=otf.load(filename,format,sub,features and features.featurefile) + if rawdata and next(rawdata) then + rawdata.lookuphash={} + tfmdata=copytotfm(rawdata,cache_id) if tfmdata and next(tfmdata) then - local features=constructors.checkedfeatures("otf",features)
- local shared=tfmdata.shared
- if not shared then
- shared={}
- tfmdata.shared=shared
- end
+ local features=constructors.checkedfeatures("otf",features) + local shared=tfmdata.shared + if not shared then + shared={} + tfmdata.shared=shared + end shared.rawdata=rawdata shared.dynamics={} - tfmdata.changed={}
- shared.features=features
- shared.processes=otf.setfeatures(tfmdata,features)
- end
- end
- containers.write(constructors.cache,cache_id,tfmdata)
- end
- return tfmdata
-end -local function read_from_otf(specification)
- local tfmdata=otftotfm(specification)
+ tfmdata.changed={} + shared.features=features + shared.processes=otf.setfeatures(tfmdata,features) + end + end + containers.write(constructors.cache,cache_id,tfmdata) + end + return tfmdata +end +local function read_from_otf(specification) + local tfmdata=otftotfm(specification) if tfmdata then - tfmdata.properties.name=specification.name
+ tfmdata.properties.name=specification.name tfmdata.properties.sub=specification.sub - tfmdata=constructors.scale(tfmdata,specification)
- local allfeatures=tfmdata.shared.features or specification.features.normal
- constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf)
+ tfmdata=constructors.scale(tfmdata,specification) + local allfeatures=tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf) constructors.setname(tfmdata,specification) - fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification)
- end
- return tfmdata
+ fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification) + end + return tfmdata end -local function checkmathsize(tfmdata,mathsize)
- local mathdata=tfmdata.shared.rawdata.metadata.math
- local mathsize=tonumber(mathsize)
+local function checkmathsize(tfmdata,mathsize) + local mathdata=tfmdata.shared.rawdata.metadata.math + local mathsize=tonumber(mathsize) if mathdata then - local parameters=tfmdata.parameters
- parameters.scriptpercentage=mathdata.ScriptPercentScaleDown
- parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown
- parameters.mathsize=mathsize
- end
-end -registerotffeature {
- name="mathsize",
- description="apply mathsize specified in the font",
- initializers={
- base=checkmathsize,
- node=checkmathsize,
- }
+ local parameters=tfmdata.parameters + parameters.scriptpercentage=mathdata.ScriptPercentScaleDown + parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown + parameters.mathsize=mathsize + end +end +registerotffeature { + name="mathsize", + description="apply mathsize specified in the font", + initializers={ + base=checkmathsize, + node=checkmathsize, + } } -function otf.collectlookups(rawdata,kind,script,language)
- local sequences=rawdata.resources.sequences
- if sequences then
- local featuremap,featurelist={},{}
- for s=1,#sequences do
- local sequence=sequences[s]
- local features=sequence.features
- features=features and features[kind]
- features=features and (features[script] or features[default] or features[wildcard])
- features=features and (features[language] or features[default] or features[wildcard])
- if features then
- local subtables=sequence.subtables
- if subtables then
- for s=1,#subtables do
- local ss=subtables[s]
- if not featuremap[s] then
- featuremap[ss]=true
- featurelist[#featurelist+1]=ss
- end
- end
- end
- end
- end
- if #featurelist>0 then
- return featuremap,featurelist
- end
- end
- return nil,nil
-end -local function check_otf(forced,specification,suffix,what)
- local name=specification.name
- if forced then
- name=file.addsuffix(name,suffix,true)
- end
- local fullname=findbinfile(name,suffix) or ""
- if fullname=="" then
- fullname=fonts.names.getfilename(name,suffix) or ""
- end
- if fullname~="" then
- specification.filename=fullname
- specification.format=what
- return read_from_otf(specification)
- end
-end -local function opentypereader(specification,suffix,what)
- local forced=specification.forced or ""
- if forced=="otf" then
- return check_otf(true,specification,forced,"opentype")
- elseif forced=="ttf" or forced=="ttc" or forced=="dfont" then
- return check_otf(true,specification,forced,"truetype")
- else
- return check_otf(false,specification,suffix,what)
- end
+function otf.collectlookups(rawdata,kind,script,language) + local sequences=rawdata.resources.sequences + if sequences then + local featuremap,featurelist={},{} + for s=1,#sequences do + local sequence=sequences[s] + local features=sequence.features + features=features and features[kind] + features=features and (features[script] or features[default] or features[wildcard]) + features=features and (features[language] or features[default] or features[wildcard]) + if features then + local subtables=sequence.subtables + if subtables then + for s=1,#subtables do + local ss=subtables[s] + if not featuremap[s] then + featuremap[ss]=true + featurelist[#featurelist+1]=ss + end + end + end + end + end + if #featurelist>0 then + return featuremap,featurelist + end + end + return nil,nil +end +local function check_otf(forced,specification,suffix,what) + local name=specification.name + if forced then + name=file.addsuffix(name,suffix,true) + end + local fullname=findbinfile(name,suffix) or "" + if fullname=="" then + fullname=fonts.names.getfilename(name,suffix) or "" + end + if fullname~="" then + specification.filename=fullname + specification.format=what + return read_from_otf(specification) + end +end +local function opentypereader(specification,suffix,what) + local forced=specification.forced or "" + if forced=="otf" then + return check_otf(true,specification,forced,"opentype") + elseif forced=="ttf" or forced=="ttc" or forced=="dfont" then + return check_otf(true,specification,forced,"truetype") + else + return check_otf(false,specification,suffix,what) + end end readers.opentype=opentypereader local formats=fonts.formats -formats.otf="opentype"
-formats.ttf="truetype"
-formats.ttc="truetype"
+formats.otf="opentype" +formats.ttf="truetype" +formats.ttc="truetype" formats.dfont="truetype" -function readers.otf (specification) return opentypereader(specification,"otf",formats.otf ) end
-function readers.ttf (specification) return opentypereader(specification,"ttf",formats.ttf ) end
-function readers.ttc (specification) return opentypereader(specification,"ttf",formats.ttc ) end
+function readers.otf (specification) return opentypereader(specification,"otf",formats.otf ) end +function readers.ttf (specification) return opentypereader(specification,"ttf",formats.ttf ) end +function readers.ttc (specification) return opentypereader(specification,"ttf",formats.ttc ) end function readers.dfont(specification) return opentypereader(specification,"ttf",formats.dfont) end -function otf.scriptandlanguage(tfmdata,attr)
- local properties=tfmdata.properties
- return properties.script or "dflt",properties.language or "dflt"
-end
+function otf.scriptandlanguage(tfmdata,attr) + local properties=tfmdata.properties + return properties.script or "dflt",properties.language or "dflt" +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-otb']={
- version=1.001,
- comment="companion to font-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
-}
-local concat=table.concat
-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=type,next,tonumber,tostring
-local lpegmatch=lpeg.match
+if not modules then modules={} end modules ['font-otb']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +local concat=table.concat +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=type,next,tonumber,tostring +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)
-local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end)
-local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end)
-local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end)
-local trace_ligatures_detail=false trackers.register("otf.ligatures.detail",function(v) trace_ligatures_detail=v end)
-local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end)
+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) +local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) +local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end) +local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end) +local trace_ligatures_detail=false trackers.register("otf.ligatures.detail",function(v) trace_ligatures_detail=v end) +local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end) local trace_preparing=false trackers.register("otf.preparing",function(v) trace_preparing=v end) local report_prepare=logs.reporter("fonts","otf prepare") -local fonts=fonts
+local fonts=fonts local otf=fonts.handlers.otf -local otffeatures=otf.features
+local otffeatures=otf.features local registerotffeature=otffeatures.register otf.defaultbasealternate="none" -local wildcard="*"
+local wildcard="*" local default="dflt" -local formatters=string.formatters
-local f_unicode=formatters["%U"]
-local f_uniname=formatters["%U (%s)"]
+local formatters=string.formatters +local f_unicode=formatters["%U"] +local f_uniname=formatters["%U (%s)"] local f_unilist=formatters["% t (% t)"] -local function gref(descriptions,n)
- if type(n)=="number" then
- local name=descriptions[n].name
- if name then
- return f_uniname(n,name)
- else
- return f_unicode(n)
- end
- elseif n then
- local num,nam={},{}
- for i=2,#n do
- local ni=n[i]
+local function gref(descriptions,n) + if type(n)=="number" then + local name=descriptions[n].name + if name then + return f_uniname(n,name) + else + return f_unicode(n) + end + elseif n then + local num,nam={},{} + for i=2,#n do + local ni=n[i] if tonumber(ni) then - local di=descriptions[ni]
- num[i]=f_unicode(ni)
- nam[i]=di and di.name or "-"
- end
- end
- return f_unilist(num,nam)
- else
- return "<error in base mode tracing>"
- end
-end -local function cref(feature,lookupname)
- if lookupname then
- return formatters["feature %a, lookup %a"](feature,lookupname)
- else
- return formatters["feature %a"](feature)
- end
-end -local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment)
- report_prepare("%s: base alternate %s => %s (%S => %S)",
- cref(feature,lookupname),
- gref(descriptions,unicode),
- replacement and gref(descriptions,replacement),
- value,
- comment)
-end -local function report_substitution(feature,lookupname,descriptions,unicode,substitution)
- report_prepare("%s: base substitution %s => %S",
- cref(feature,lookupname),
- gref(descriptions,unicode),
- gref(descriptions,substitution))
-end -local function report_ligature(feature,lookupname,descriptions,unicode,ligature)
- report_prepare("%s: base ligature %s => %S",
- cref(feature,lookupname),
- gref(descriptions,ligature),
- gref(descriptions,unicode))
-end -local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value)
- report_prepare("%s: base kern %s + %s => %S",
- cref(feature,lookupname),
- gref(descriptions,unicode),
- gref(descriptions,otherunicode),
- value)
-end -local basemethods={}
+ local di=descriptions[ni] + num[i]=f_unicode(ni) + nam[i]=di and di.name or "-" + end + end + return f_unilist(num,nam) + else + return "<error in base mode tracing>" + end +end +local function cref(feature,lookupname) + if lookupname then + return formatters["feature %a, lookup %a"](feature,lookupname) + else + return formatters["feature %a"](feature) + end +end +local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment) + report_prepare("%s: base alternate %s => %s (%S => %S)", + cref(feature,lookupname), + gref(descriptions,unicode), + replacement and gref(descriptions,replacement), + value, + comment) +end +local function report_substitution(feature,lookupname,descriptions,unicode,substitution) + report_prepare("%s: base substitution %s => %S", + cref(feature,lookupname), + gref(descriptions,unicode), + gref(descriptions,substitution)) +end +local function report_ligature(feature,lookupname,descriptions,unicode,ligature) + report_prepare("%s: base ligature %s => %S", + cref(feature,lookupname), + gref(descriptions,ligature), + gref(descriptions,unicode)) +end +local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value) + report_prepare("%s: base kern %s + %s => %S", + cref(feature,lookupname), + gref(descriptions,unicode), + gref(descriptions,otherunicode), + value) +end +local basemethods={} local basemethod="<unset>" -local function applybasemethod(what,...)
- local m=basemethods[basemethod][what]
- if m then
- return m(...)
- end
+local function applybasemethod(what,...) + local m=basemethods[basemethod][what] + if m then + return m(...) + end end local basehash,basehashes,applied={},1,{} -local function registerbasehash(tfmdata)
- local properties=tfmdata.properties
- local hash=concat(applied," ")
- local base=basehash[hash]
- if not base then
- basehashes=basehashes+1
- base=basehashes
- basehash[hash]=base
- end
- properties.basehash=base
+local function registerbasehash(tfmdata) + local properties=tfmdata.properties + local hash=concat(applied," ") + local base=basehash[hash] + if not base then + basehashes=basehashes+1 + base=basehashes + basehash[hash]=base + end + properties.basehash=base properties.fullname=properties.fullname.."-"..base - applied={}
+ applied={} end -local function registerbasefeature(feature,value)
- applied[#applied+1]=feature.."="..tostring(value)
+local function registerbasefeature(feature,value) + applied[#applied+1]=feature.."="..tostring(value) end local trace=false -local function finalize_ligatures(tfmdata,ligatures)
- local nofligatures=#ligatures
- if nofligatures>0 then
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local resources=tfmdata.resources
- local unicodes=resources.unicodes
- local private=resources.private
- local alldone=false
- while not alldone do
- local done=0
- for i=1,nofligatures do
- local ligature=ligatures[i]
- if ligature then
- local unicode,lookupdata=ligature[1],ligature[2]
- if trace then
- trace_ligatures_detail("building % a into %a",lookupdata,unicode)
- end
- local size=#lookupdata
+local function finalize_ligatures(tfmdata,ligatures) + local nofligatures=#ligatures + if nofligatures>0 then + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local unicodes=resources.unicodes + local private=resources.private + local alldone=false + while not alldone do + local done=0 + for i=1,nofligatures do + local ligature=ligatures[i] + if ligature then + local unicode,lookupdata=ligature[1],ligature[2] + if trace then + trace_ligatures_detail("building % a into %a",lookupdata,unicode) + end + local size=#lookupdata local firstcode=lookupdata[1] - local firstdata=characters[firstcode]
- local okay=false
- if firstdata then
- local firstname="ctx_"..firstcode
+ local firstdata=characters[firstcode] + local okay=false + if firstdata then + local firstname="ctx_"..firstcode for i=1,size-1 do - local firstdata=characters[firstcode]
- if not firstdata then
- firstcode=private
- if trace then
- trace_ligatures_detail("defining %a as %a",firstname,firstcode)
- end
- unicodes[firstname]=firstcode
- firstdata={ intermediate=true,ligatures={} }
- characters[firstcode]=firstdata
- descriptions[firstcode]={ name=firstname }
- private=private+1
- end
- local target
- local secondcode=lookupdata[i+1]
- local secondname=firstname.."_"..secondcode
- if i==size-1 then
- target=unicode
- if not unicodes[secondname] then
+ local firstdata=characters[firstcode] + if not firstdata then + firstcode=private + if trace then + trace_ligatures_detail("defining %a as %a",firstname,firstcode) + end + unicodes[firstname]=firstcode + firstdata={ intermediate=true,ligatures={} } + characters[firstcode]=firstdata + descriptions[firstcode]={ name=firstname } + private=private+1 + end + local target + local secondcode=lookupdata[i+1] + local secondname=firstname.."_"..secondcode + if i==size-1 then + target=unicode + if not unicodes[secondname] then unicodes[secondname]=unicode - end
- okay=true
- else
- target=unicodes[secondname]
- if not target then
- break
- end
- end
- if trace then
- trace_ligatures_detail("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target)
- end
- local firstligs=firstdata.ligatures
- if firstligs then
- firstligs[secondcode]={ char=target }
- else
- firstdata.ligatures={ [secondcode]={ char=target } }
- end
- firstcode=target
- firstname=secondname
- end
- end
- if okay then
- ligatures[i]=false
- done=done+1
- end
- end
- end
- alldone=done==0
- end
- if trace then
- for k,v in next,characters do
- if v.ligatures then table.print(v,k) end
- end
- end
- tfmdata.resources.private=private
- end
-end -local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local resources=tfmdata.resources
- local changed=tfmdata.changed
- local unicodes=resources.unicodes
- local lookuphash=resources.lookuphash
+ end + okay=true + else + target=unicodes[secondname] + if not target then + break + end + end + if trace then + trace_ligatures_detail("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target) + end + local firstligs=firstdata.ligatures + if firstligs then + firstligs[secondcode]={ char=target } + else + firstdata.ligatures={ [secondcode]={ char=target } } + end + firstcode=target + firstname=secondname + end + end + if okay then + ligatures[i]=false + done=done+1 + end + end + end + alldone=done==0 + end + if trace then + for k,v in next,characters do + if v.ligatures then table.print(v,k) end + end + end + tfmdata.resources.private=private + end +end +local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local changed=tfmdata.changed + local unicodes=resources.unicodes + local lookuphash=resources.lookuphash local lookuptypes=resources.lookuptypes - local ligatures={}
- local alternate=tonumber(value)
+ local ligatures={} + local alternate=tonumber(value) local defaultalt=otf.defaultbasealternate - local trace_singles=trace_baseinit and trace_singles
- local trace_alternatives=trace_baseinit and trace_alternatives
+ local trace_singles=trace_baseinit and trace_singles + local trace_alternatives=trace_baseinit and trace_alternatives local trace_ligatures=trace_baseinit and trace_ligatures - local actions={
- substitution=function(lookupdata,lookupname,description,unicode)
- if trace_singles then
- report_substitution(feature,lookupname,descriptions,unicode,lookupdata)
- end
- changed[unicode]=lookupdata
- end,
- alternate=function(lookupdata,lookupname,description,unicode)
- local replacement=lookupdata[alternate]
- if replacement then
- changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
- end
- elseif defaultalt=="first" then
- replacement=lookupdata[1]
- changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
- end
- elseif defaultalt=="last" then
- replacement=lookupdata[#data]
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
- end
- else
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
- end
- end
- end,
- ligature=function(lookupdata,lookupname,description,unicode)
- if trace_ligatures then
- report_ligature(feature,lookupname,descriptions,unicode,lookupdata)
- end
- ligatures[#ligatures+1]={ unicode,lookupdata }
- end,
+ local actions={ + substitution=function(lookupdata,lookupname,description,unicode) + if trace_singles then + report_substitution(feature,lookupname,descriptions,unicode,lookupdata) + end + changed[unicode]=lookupdata + end, + alternate=function(lookupdata,lookupname,description,unicode) + local replacement=lookupdata[alternate] + if replacement then + changed[unicode]=replacement + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + end + elseif defaultalt=="first" then + replacement=lookupdata[1] + changed[unicode]=replacement + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + end + elseif defaultalt=="last" then + replacement=lookupdata[#data] + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + end + else + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + end + end + end, + ligature=function(lookupdata,lookupname,description,unicode) + if trace_ligatures then + report_ligature(feature,lookupname,descriptions,unicode,lookupdata) + end + ligatures[#ligatures+1]={ unicode,lookupdata } + end, } - for unicode,character in next,characters do
- local description=descriptions[unicode]
- local lookups=description.slookups
- if lookups then
- for l=1,#lookuplist do
- local lookupname=lookuplist[l]
- local lookupdata=lookups[lookupname]
- if lookupdata then
- local lookuptype=lookuptypes[lookupname]
- local action=actions[lookuptype]
- if action then
- action(lookupdata,lookupname,description,unicode)
- end
- end
- end
- end
- local lookups=description.mlookups
- if lookups then
- for l=1,#lookuplist do
- local lookupname=lookuplist[l]
- local lookuplist=lookups[lookupname]
- if lookuplist then
- local lookuptype=lookuptypes[lookupname]
- local action=actions[lookuptype]
- if action then
- for i=1,#lookuplist do
- action(lookuplist[i],lookupname,description,unicode)
- end
- end
- end
- end
- end
- end - finalize_ligatures(tfmdata,ligatures)
+ for unicode,character in next,characters do + local description=descriptions[unicode] + local lookups=description.slookups + if lookups then + for l=1,#lookuplist do + local lookupname=lookuplist[l] + local lookupdata=lookups[lookupname] + if lookupdata then + local lookuptype=lookuptypes[lookupname] + local action=actions[lookuptype] + if action then + action(lookupdata,lookupname,description,unicode) + end + end + end + end + local lookups=description.mlookups + if lookups then + for l=1,#lookuplist do + local lookupname=lookuplist[l] + local lookuplist=lookups[lookupname] + if lookuplist then + local lookuptype=lookuptypes[lookupname] + local action=actions[lookuptype] + if action then + for i=1,#lookuplist do + action(lookuplist[i],lookupname,description,unicode) + end + end + end + end + end + end + finalize_ligatures(tfmdata,ligatures) end local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) - local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local resources=tfmdata.resources
- local unicodes=resources.unicodes
- local sharedkerns={}
- local traceindeed=trace_baseinit and trace_kerns
- for unicode,character in next,characters do
- local description=descriptions[unicode]
+ local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local unicodes=resources.unicodes + local sharedkerns={} + local traceindeed=trace_baseinit and trace_kerns + for unicode,character in next,characters do + local description=descriptions[unicode] local rawkerns=description.kerns - if rawkerns then
- local s=sharedkerns[rawkerns]
+ if rawkerns then + local s=sharedkerns[rawkerns] if s==false then - elseif s then
- character.kerns=s
- else
- local newkerns=character.kerns
- local done=false
- for l=1,#lookuplist do
- local lookup=lookuplist[l]
- local kerns=rawkerns[lookup]
- if kerns then
- for otherunicode,value in next,kerns do
+ elseif s then + character.kerns=s + else + local newkerns=character.kerns + local done=false + for l=1,#lookuplist do + local lookup=lookuplist[l] + local kerns=rawkerns[lookup] + if kerns then + for otherunicode,value in next,kerns do if value==0 then - elseif not newkerns then
- newkerns={ [otherunicode]=value }
- done=true
- if traceindeed then
- report_kern(feature,lookup,descriptions,unicode,otherunicode,value)
- end
+ elseif not newkerns then + newkerns={ [otherunicode]=value } + done=true + if traceindeed then + report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + end elseif not newkerns[otherunicode] then - newkerns[otherunicode]=value
- done=true
- if traceindeed then
- report_kern(feature,lookup,descriptions,unicode,otherunicode,value)
- end
- end
- end
- end
- end
- if done then
- sharedkerns[rawkerns]=newkerns
+ newkerns[otherunicode]=value + done=true + if traceindeed then + report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + end + end + end + end + end + if done then + sharedkerns[rawkerns]=newkerns character.kerns=newkerns - else
- sharedkerns[rawkerns]=false
- end
- end
- end
- end
-end -basemethods.independent={
- preparesubstitutions=preparesubstitutions,
- preparepositionings=preparepositionings,
+ else + sharedkerns[rawkerns]=false + end + end + end + end +end +basemethods.independent={ + preparesubstitutions=preparesubstitutions, + preparepositionings=preparepositionings, } -local function makefake(tfmdata,name,present)
- local resources=tfmdata.resources
- local private=resources.private
- local character={ intermediate=true,ligatures={} }
- resources.unicodes[name]=private
- tfmdata.characters[private]=character
- tfmdata.descriptions[private]={ name=name }
- resources.private=private+1
- present[name]=private
- return character
-end -local function make_1(present,tree,name)
- for k,v in next,tree do
- if k=="ligature" then
- present[name]=v
- else
- make_1(present,v,name.."_"..k)
- end
- end
-end -local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname)
- for k,v in next,tree do
- if k=="ligature" then
- local character=characters[preceding]
- if not character then
- if trace_baseinit then
- report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding)
- end
- character=makefake(tfmdata,name,present)
- end
- local ligatures=character.ligatures
- if ligatures then
- ligatures[unicode]={ char=v }
- else
- character.ligatures={ [unicode]={ char=v } }
- end
- if done then
- local d=done[lookupname]
- if not d then
- done[lookupname]={ "dummy",v }
- else
- d[#d+1]=v
- end
- end
- else
- local code=present[name] or unicode
- local name=name.."_"..k
- make_2(present,tfmdata,characters,v,name,code,k,done,lookupname)
- end
- end
-end -local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local resources=tfmdata.resources
- local changed=tfmdata.changed
- local lookuphash=resources.lookuphash
+local function makefake(tfmdata,name,present) + local resources=tfmdata.resources + local private=resources.private + local character={ intermediate=true,ligatures={} } + resources.unicodes[name]=private + tfmdata.characters[private]=character + tfmdata.descriptions[private]={ name=name } + resources.private=private+1 + present[name]=private + return character +end +local function make_1(present,tree,name) + for k,v in next,tree do + if k=="ligature" then + present[name]=v + else + make_1(present,v,name.."_"..k) + end + end +end +local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname) + for k,v in next,tree do + if k=="ligature" then + local character=characters[preceding] + if not character then + if trace_baseinit then + report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding) + end + character=makefake(tfmdata,name,present) + end + local ligatures=character.ligatures + if ligatures then + ligatures[unicode]={ char=v } + else + character.ligatures={ [unicode]={ char=v } } + end + if done then + local d=done[lookupname] + if not d then + done[lookupname]={ "dummy",v } + else + d[#d+1]=v + end + end + else + local code=present[name] or unicode + local name=name.."_"..k + make_2(present,tfmdata,characters,v,name,code,k,done,lookupname) + end + end +end +local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local changed=tfmdata.changed + local lookuphash=resources.lookuphash local lookuptypes=resources.lookuptypes - local ligatures={}
- local alternate=tonumber(value)
+ local ligatures={} + local alternate=tonumber(value) local defaultalt=otf.defaultbasealternate - local trace_singles=trace_baseinit and trace_singles
- local trace_alternatives=trace_baseinit and trace_alternatives
+ local trace_singles=trace_baseinit and trace_singles + local trace_alternatives=trace_baseinit and trace_alternatives local trace_ligatures=trace_baseinit and trace_ligatures - for l=1,#lookuplist do
- local lookupname=lookuplist[l]
- local lookupdata=lookuphash[lookupname]
- local lookuptype=lookuptypes[lookupname]
- for unicode,data in next,lookupdata do
- if lookuptype=="substitution" then
- if trace_singles then
- report_substitution(feature,lookupname,descriptions,unicode,data)
- end
- changed[unicode]=data
- elseif lookuptype=="alternate" then
- local replacement=data[alternate]
- if replacement then
- changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
- end
- elseif defaultalt=="first" then
- replacement=data[1]
- changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
- end
- elseif defaultalt=="last" then
- replacement=data[#data]
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
- end
- else
- if trace_alternatives then
- report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
- end
- end
- elseif lookuptype=="ligature" then
- ligatures[#ligatures+1]={ unicode,data,lookupname }
- if trace_ligatures then
- report_ligature(feature,lookupname,descriptions,unicode,data)
- end
- end
- end
+ for l=1,#lookuplist do + local lookupname=lookuplist[l] + local lookupdata=lookuphash[lookupname] + local lookuptype=lookuptypes[lookupname] + for unicode,data in next,lookupdata do + if lookuptype=="substitution" then + if trace_singles then + report_substitution(feature,lookupname,descriptions,unicode,data) + end + changed[unicode]=data + elseif lookuptype=="alternate" then + local replacement=data[alternate] + if replacement then + changed[unicode]=replacement + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + end + elseif defaultalt=="first" then + replacement=data[1] + changed[unicode]=replacement + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + end + elseif defaultalt=="last" then + replacement=data[#data] + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + end + else + if trace_alternatives then + report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + end + end + elseif lookuptype=="ligature" then + ligatures[#ligatures+1]={ unicode,data,lookupname } + if trace_ligatures then + report_ligature(feature,lookupname,descriptions,unicode,data) + end + end + end end local nofligatures=#ligatures if nofligatures>0 then - local characters=tfmdata.characters
- local present={}
+ local characters=tfmdata.characters + local present={} local done=trace_baseinit and trace_ligatures and {} - for i=1,nofligatures do
- local ligature=ligatures[i]
- local unicode,tree=ligature[1],ligature[2]
- make_1(present,tree,"ctx_"..unicode)
+ for i=1,nofligatures do + local ligature=ligatures[i] + local unicode,tree=ligature[1],ligature[2] + make_1(present,tree,"ctx_"..unicode) end - for i=1,nofligatures do
- local ligature=ligatures[i]
- local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3]
- make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname)
+ for i=1,nofligatures do + local ligature=ligatures[i] + local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3] + make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname) end end end -local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local resources=tfmdata.resources
- local lookuphash=resources.lookuphash
+local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local lookuphash=resources.lookuphash local traceindeed=trace_baseinit and trace_kerns - for l=1,#lookuplist do
- local lookupname=lookuplist[l]
- local lookupdata=lookuphash[lookupname]
- for unicode,data in next,lookupdata do
- local character=characters[unicode]
- local kerns=character.kerns
- if not kerns then
- kerns={}
- character.kerns=kerns
- end
- if traceindeed then
- for otherunicode,kern in next,data do
- if not kerns[otherunicode] and kern~=0 then
- kerns[otherunicode]=kern
- report_kern(feature,lookup,descriptions,unicode,otherunicode,kern)
- end
- end
- else
- for otherunicode,kern in next,data do
- if not kerns[otherunicode] and kern~=0 then
- kerns[otherunicode]=kern
- end
- end
- end
- end
- end -end -local function initializehashes(tfmdata)
- nodeinitializers.features(tfmdata)
-end -basemethods.shared={
- initializehashes=initializehashes,
- preparesubstitutions=preparesubstitutions,
- preparepositionings=preparepositionings,
+ for l=1,#lookuplist do + local lookupname=lookuplist[l] + local lookupdata=lookuphash[lookupname] + for unicode,data in next,lookupdata do + local character=characters[unicode] + local kerns=character.kerns + if not kerns then + kerns={} + character.kerns=kerns + end + if traceindeed then + for otherunicode,kern in next,data do + if not kerns[otherunicode] and kern~=0 then + kerns[otherunicode]=kern + report_kern(feature,lookup,descriptions,unicode,otherunicode,kern) + end + end + else + for otherunicode,kern in next,data do + if not kerns[otherunicode] and kern~=0 then + kerns[otherunicode]=kern + end + end + end + end + end +end +local function initializehashes(tfmdata) + nodeinitializers.features(tfmdata) +end +basemethods.shared={ + initializehashes=initializehashes, + preparesubstitutions=preparesubstitutions, + preparepositionings=preparepositionings, } basemethod="independent" -local function featuresinitializer(tfmdata,value)
+local function featuresinitializer(tfmdata,value) if true then - local t=trace_preparing and os.clock()
- local features=tfmdata.shared.features
- if features then
- applybasemethod("initializehashes",tfmdata)
- local collectlookups=otf.collectlookups
- local rawdata=tfmdata.shared.rawdata
- local properties=tfmdata.properties
- local script=properties.script
- local language=properties.language
- local basesubstitutions=rawdata.resources.features.gsub
- local basepositionings=rawdata.resources.features.gpos
- if basesubstitutions then
- for feature,data in next,basesubstitutions do
- local value=features[feature]
- if value then
- local validlookups,lookuplist=collectlookups(rawdata,feature,script,language)
- if validlookups then
- applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist)
- registerbasefeature(feature,value)
- end
- end
- end
- end
- if basepositionings then
- for feature,data in next,basepositionings do
- local value=features[feature]
- if value then
- local validlookups,lookuplist=collectlookups(rawdata,feature,script,language)
- if validlookups then
- applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist)
- registerbasefeature(feature,value)
- end
- end
- end
- end
- registerbasehash(tfmdata)
- end
- if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %a",os.clock()-t,tfmdata.properties.fullname)
- end
- end
-end -registerotffeature {
- name="features",
- description="features",
- default=true,
+ local t=trace_preparing and os.clock() + local features=tfmdata.shared.features + if features then + applybasemethod("initializehashes",tfmdata) + local collectlookups=otf.collectlookups + local rawdata=tfmdata.shared.rawdata + local properties=tfmdata.properties + local script=properties.script + local language=properties.language + local basesubstitutions=rawdata.resources.features.gsub + local basepositionings=rawdata.resources.features.gpos + if basesubstitutions then + for feature,data in next,basesubstitutions do + local value=features[feature] + if value then + local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) + if validlookups then + applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist) + registerbasefeature(feature,value) + end + end + end + end + if basepositionings then + for feature,data in next,basepositionings do + local value=features[feature] + if value then + local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) + if validlookups then + applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist) + registerbasefeature(feature,value) + end + end + end + end + registerbasehash(tfmdata) + end + if trace_preparing then + report_prepare("preparation time is %0.3f seconds for %a",os.clock()-t,tfmdata.properties.fullname) + end + end +end +registerotffeature { + name="features", + description="features", + default=true, initializers={ - base=featuresinitializer,
- }
+ base=featuresinitializer, + } } -directives.register("fonts.otf.loader.basemethod",function(v)
- if basemethods[v] then
- basemethod=v
- end
-end)
+directives.register("fonts.otf.loader.basemethod",function(v) + if basemethods[v] then + basemethod=v + end +end) end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['node-inj']={
- version=1.001,
- comment="companion to node-ini.mkiv",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files",
+if not modules then modules={} end modules ['node-inj']={ + version=1.001, + comment="companion to node-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } -local next=next
+local next=next local utfchar=utf.char local trace_injections=false trackers.register("nodes.injections",function(v) trace_injections=v end) local report_injections=logs.reporter("nodes","injections") local attributes,nodes,node=attributes,nodes,node -fonts=fonts
+fonts=fonts local fontdata=fonts.hashes.identifiers -nodes.injections=nodes.injections or {}
+nodes.injections=nodes.injections or {} local injections=nodes.injections -local nodecodes=nodes.nodecodes
-local glyph_code=nodecodes.glyph
-local kern_code=nodecodes.kern
-local nodepool=nodes.pool
+local nodecodes=nodes.nodecodes +local glyph_code=nodecodes.glyph +local kern_code=nodecodes.kern +local nodepool=nodes.pool local newkern=nodepool.kern -local traverse_id=node.traverse_id
-local insert_node_before=node.insert_before
+local traverse_id=node.traverse_id +local insert_node_before=node.insert_before local insert_node_after=node.insert_after -local a_kernpair=attributes.private('kernpair')
-local a_ligacomp=attributes.private('ligacomp')
-local a_markbase=attributes.private('markbase')
-local a_markmark=attributes.private('markmark')
-local a_markdone=attributes.private('markdone')
-local a_cursbase=attributes.private('cursbase')
-local a_curscurs=attributes.private('curscurs')
+local a_kernpair=attributes.private('kernpair') +local a_ligacomp=attributes.private('ligacomp') +local a_markbase=attributes.private('markbase') +local a_markmark=attributes.private('markmark') +local a_markdone=attributes.private('markdone') +local a_cursbase=attributes.private('cursbase') +local a_curscurs=attributes.private('curscurs') local a_cursdone=attributes.private('cursdone') -function injections.installnewkern(nk)
- newkern=nk or newkern
+function injections.installnewkern(nk) + newkern=nk or newkern end -local cursives={}
-local marks={}
+local cursives={} +local marks={} local kerns={} -function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
- local ws,wn=tfmstart.width,tfmnext.width
- local bound=#cursives+1
- start[a_cursbase]=bound
- nxt[a_curscurs]=bound
- cursives[bound]={ rlmode,dx,dy,ws,wn }
- return dx,dy,bound
-end -function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) + local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2]) + local ws,wn=tfmstart.width,tfmnext.width + local bound=#cursives+1 + start[a_cursbase]=bound + nxt[a_curscurs]=bound + cursives[bound]={ rlmode,dx,dy,ws,wn } + return dx,dy,bound +end +function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr) local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4] - if x~=0 or w~=0 or y~=0 or h~=0 then
- local bound=current[a_kernpair]
- if bound then
+ if x~=0 or w~=0 or y~=0 or h~=0 then + local bound=current[a_kernpair] + if bound then local kb=kerns[bound] - kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
- else
- bound=#kerns+1
- current[a_kernpair]=bound
- kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
- end
- return x,y,w,h,bound
- end
+ kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h + else + bound=#kerns+1 + current[a_kernpair]=bound + kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width } + end + return x,y,w,h,bound + end return x,y,w,h end -function injections.setkern(current,factor,rlmode,x,tfmchr)
- local dx=factor*x
- if dx~=0 then
- local bound=#kerns+1
- current[a_kernpair]=bound
- kerns[bound]={ rlmode,dx }
- return dx,bound
- else
- return 0,0
- end
+function injections.setkern(current,factor,rlmode,x,tfmchr) + local dx=factor*x + if dx~=0 then + local bound=#kerns+1 + current[a_kernpair]=bound + kerns[bound]={ rlmode,dx } + return dx,bound + else + return 0,0 + end end function injections.setmark(start,base,factor,rlmode,ba,ma,index) local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) local bound=base[a_markbase] - local index=1
- if bound then
- local mb=marks[bound]
+ local index=1 + if bound then + local mb=marks[bound] if mb then - index=#mb+1
- mb[index]={ dx,dy,rlmode }
- start[a_markmark]=bound
- start[a_markdone]=index
- return dx,dy,bound
- else
- report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
- end
- end - index=index or 1
- bound=#marks+1
- base[a_markbase]=bound
- start[a_markmark]=bound
- start[a_markdone]=index
- marks[bound]={ [index]={ dx,dy,rlmode } }
- return dx,dy,bound
-end -local function dir(n)
- return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
-end -local function trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if n.subtype<256 then
- local kp=n[a_kernpair]
- local mb=n[a_markbase]
- local mm=n[a_markmark]
- local md=n[a_markdone]
- local cb=n[a_cursbase]
- local cc=n[a_curscurs]
- local char=n.char
- report_injections("font %s, char %U, glyph %c",n.font,char,char)
- if kp then
- local k=kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
- else
- report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
- end
- end
- if mb then
- report_injections(" markbase: bound %a",mb)
- end
- if mm then
- local m=marks[mm]
- if mb then
- local m=m[mb]
- if m then
- report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
- else
- report_injections(" markmark: bound %a, missing index",mm)
- end
- else
- m=m[1]
- report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
- end
- end
- if cb then
- report_injections(" cursbase: bound %a",cb)
- end
- if cc then
- local c=cursives[cc]
- report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
- end
- end
- end
- report_injections("end run")
-end -local function show_result(head)
- local current=head
- local skipping=false
- while current do
- local id=current.id
- if id==glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
- skipping=false
- elseif id==kern_code then
- report_injections("kern: %p",current.kern)
- skipping=false
- elseif not skipping then
- report_injections()
- skipping=true
- end
- current=current.next
- end
-end -function injections.handler(head,where,keep)
- local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
- if has_marks or has_cursives then
- if trace_injections then
- trace(head)
- end - local done,ky,rl,valid,cx,wx,mk,nofvalid=false,{},{},{},{},{},{},0
+ index=#mb+1 + mb[index]={ dx,dy,rlmode } + start[a_markmark]=bound + start[a_markdone]=index + return dx,dy,bound + else + report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound) + end + end + index=index or 1 + bound=#marks+1 + base[a_markbase]=bound + start[a_markmark]=bound + start[a_markdone]=index + marks[bound]={ [index]={ dx,dy,rlmode } } + return dx,dy,bound +end +local function dir(n) + return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" +end +local function trace(head) + report_injections("begin run") + for n in traverse_id(glyph_code,head) do + if n.subtype<256 then + local kp=n[a_kernpair] + local mb=n[a_markbase] + local mm=n[a_markmark] + local md=n[a_markdone] + local cb=n[a_cursbase] + local cc=n[a_curscurs] + local char=n.char + report_injections("font %s, char %U, glyph %c",n.font,char,char) + if kp then + local k=kerns[kp] + if k[3] then + report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5]) + else + report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2]) + end + end + if mb then + report_injections(" markbase: bound %a",mb) + end + if mm then + local m=marks[mm] + if mb then + local m=m[mb] + if m then + report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2]) + else + report_injections(" markmark: bound %a, missing index",mm) + end + else + m=m[1] + report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2]) + end + end + if cb then + report_injections(" cursbase: bound %a",cb) + end + if cc then + local c=cursives[cc] + report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3]) + end + end + end + report_injections("end run") +end +local function show_result(head) + local current=head + local skipping=false + while current do + local id=current.id + if id==glyph_code then + report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset) + skipping=false + elseif id==kern_code then + report_injections("kern: %p",current.kern) + skipping=false + elseif not skipping then + report_injections() + skipping=true + end + current=current.next + end +end +function injections.handler(head,where,keep) + local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns) + if has_marks or has_cursives then + if trace_injections then + trace(head) + end + local done,ky,rl,valid,cx,wx,mk,nofvalid=false,{},{},{},{},{},{},0 if has_kerns then - local nf,tm=nil,nil
+ local nf,tm=nil,nil for n in traverse_id(glyph_code,head) do - if n.subtype<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- if n.font~=nf then
- nf=n.font
- tm=fontdata[nf].resources.marks
- end
- if tm then
- mk[n]=tm[n.char]
- end
- local k=n[a_kernpair]
- if k then
- local kk=kerns[k]
- if kk then
- local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0
- local dy=y-h
- if dy~=0 then
- ky[n]=dy
- end
- if w~=0 or x~=0 then
- wx[n]=kk
- end
+ if n.subtype<256 then + nofvalid=nofvalid+1 + valid[nofvalid]=n + if n.font~=nf then + nf=n.font + tm=fontdata[nf].resources.marks + end + if tm then + mk[n]=tm[n.char] + end + local k=n[a_kernpair] + if k then + local kk=kerns[k] + if kk then + local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0 + local dy=y-h + if dy~=0 then + ky[n]=dy + end + if w~=0 or x~=0 then + wx[n]=kk + end rl[n]=kk[1] - end
- end
- end
- end
- else
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if n.subtype<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- if n.font~=nf then
- nf=n.font
- tm=fontdata[nf].resources.marks
- end
- if tm then
- mk[n]=tm[n.char]
- end
- end
- end
- end
+ end + end + end + end + else + local nf,tm=nil,nil + for n in traverse_id(glyph_code,head) do + if n.subtype<256 then + nofvalid=nofvalid+1 + valid[nofvalid]=n + if n.font~=nf then + nf=n.font + tm=fontdata[nf].resources.marks + end + if tm then + mk[n]=tm[n.char] + end + end + end + end if nofvalid>0 then - local cx={}
- if has_kerns and next(ky) then
- for n,k in next,ky do
- n.yoffset=k
- end
+ local cx={} + if has_kerns and next(ky) then + for n,k in next,ky do + n.yoffset=k + end end - if has_cursives then
+ if has_cursives then local p_cursbase,p=nil,nil - local t,d,maxt={},{},0
+ local t,d,maxt={},{},0 for i=1,nofvalid do - local n=valid[i]
- if not mk[n] then
- local n_cursbase=n[a_cursbase]
- if p_cursbase then
- local n_curscurs=n[a_curscurs]
- if p_cursbase==n_curscurs then
- local c=cursives[n_curscurs]
- if c then
- local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5]
- if rlmode>=0 then
- dx=dx-ws
- else
- dx=dx+wn
- end
- if dx~=0 then
- cx[n]=dx
- rl[n]=rlmode
+ local n=valid[i] + if not mk[n] then + local n_cursbase=n[a_cursbase] + if p_cursbase then + local n_curscurs=n[a_curscurs] + if p_cursbase==n_curscurs then + local c=cursives[n_curscurs] + if c then + local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5] + if rlmode>=0 then + dx=dx-ws + else + dx=dx+wn + end + if dx~=0 then + cx[n]=dx + rl[n]=rlmode end dy=-dy - maxt=maxt+1
- t[maxt]=p
- d[maxt]=dy
- else
- maxt=0
- end
- end
- elseif maxt>0 then
- local ny=n.yoffset
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- ti.yoffset=ti.yoffset+ny
- end
- maxt=0
- end
- if not n_cursbase and maxt>0 then
- local ny=n.yoffset
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- ti.yoffset=ny
- end
- maxt=0
- end
- p_cursbase,p=n_cursbase,n
- end
- end
- if maxt>0 then
- local ny=n.yoffset
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- ti.yoffset=ny
- end
- maxt=0
- end
- if not keep then
- cursives={}
- end
- end
- if has_marks then
- for i=1,nofvalid do
- local p=valid[i]
- local p_markbase=p[a_markbase]
- if p_markbase then
- local mrks=marks[p_markbase]
- local nofmarks=#mrks
- for n in traverse_id(glyph_code,p.next) do
- local n_markmark=n[a_markmark]
- if p_markbase==n_markmark then
- local index=n[a_markdone] or 1
- local d=mrks[index]
- if d then
+ maxt=maxt+1 + t[maxt]=p + d[maxt]=dy + else + maxt=0 + end + end + elseif maxt>0 then + local ny=n.yoffset + for i=maxt,1,-1 do + ny=ny+d[i] + local ti=t[i] + ti.yoffset=ti.yoffset+ny + end + maxt=0 + end + if not n_cursbase and maxt>0 then + local ny=n.yoffset + for i=maxt,1,-1 do + ny=ny+d[i] + local ti=t[i] + ti.yoffset=ny + end + maxt=0 + end + p_cursbase,p=n_cursbase,n + end + end + if maxt>0 then + local ny=n.yoffset + for i=maxt,1,-1 do + ny=ny+d[i] + local ti=t[i] + ti.yoffset=ny + end + maxt=0 + end + if not keep then + cursives={} + end + end + if has_marks then + for i=1,nofvalid do + local p=valid[i] + local p_markbase=p[a_markbase] + if p_markbase then + local mrks=marks[p_markbase] + local nofmarks=#mrks + for n in traverse_id(glyph_code,p.next) do + local n_markmark=n[a_markmark] + if p_markbase==n_markmark then + local index=n[a_markdone] or 1 + local d=mrks[index] + if d then local rlmode=d[3] - local k=wx[p]
- if k then
- local x=k[2]
- local w=k[4]
- if w then
+ local k=wx[p] + if k then + local x=k[2] + local w=k[4] + if w then if rlmode and rlmode>=0 then - n.xoffset=p.xoffset-p.width+d[1]-(w-x)
+ n.xoffset=p.xoffset-p.width+d[1]-(w-x) else - n.xoffset=p.xoffset-d[1]-x
- end
- else
+ n.xoffset=p.xoffset-d[1]-x + end + else if rlmode and rlmode>=0 then - n.xoffset=p.xoffset-p.width+d[1]
+ n.xoffset=p.xoffset-p.width+d[1] else - n.xoffset=p.xoffset-d[1]-x
- end
- end
- else
- if rlmode and rlmode>=0 then
- n.xoffset=p.xoffset-p.width+d[1]
- else
- n.xoffset=p.xoffset-d[1]
- end
+ n.xoffset=p.xoffset-d[1]-x + end + end + else + if rlmode and rlmode>=0 then + n.xoffset=p.xoffset-p.width+d[1] + else + n.xoffset=p.xoffset-d[1] + end end - if mk[p] then
- n.yoffset=p.yoffset+d[2]
- else
- n.yoffset=n.yoffset+p.yoffset+d[2]
+ if mk[p] then + n.yoffset=p.yoffset+d[2] + else + n.yoffset=n.yoffset+p.yoffset+d[2] end - if nofmarks==1 then
- break
- else
- nofmarks=nofmarks-1
- end
- end
+ if nofmarks==1 then + break + else + nofmarks=nofmarks-1 + end + end else - end
- end
- end
- end
- if not keep then
- marks={}
- end
- end - if next(wx) then
+ end + end + end + end + if not keep then + marks={} + end + end + if next(wx) then for n,k in next,wx do - local x=k[2]
- local w=k[4]
- if w then
+ local x=k[2] + local w=k[4] + if w then local rl=k[1] - local wx=w-x
+ local wx=w-x if rl<0 then - if wx~=0 then
+ if wx~=0 then insert_node_before(head,n,newkern(wx)) - end
- if x~=0 then
+ end + if x~=0 then insert_node_after (head,n,newkern(x)) - end
- else
- if x~=0 then
+ end + else + if x~=0 then insert_node_before(head,n,newkern(x)) - end
- if wx~=0 then
+ end + if wx~=0 then insert_node_after (head,n,newkern(wx)) - end
- end
+ end + end elseif x~=0 then insert_node_before(head,n,newkern(x)) - end
- end
- end
- if next(cx) then
- for n,k in next,cx do
- if k~=0 then
- local rln=rl[n]
- if rln and rln<0 then
+ end + end + end + if next(cx) then + for n,k in next,cx do + if k~=0 then + local rln=rl[n] + if rln and rln<0 then insert_node_before(head,n,newkern(-k)) - else
+ else insert_node_before(head,n,newkern(k)) - end
- end
- end
- end
- if not keep then
- kerns={}
- end - return head,true
- elseif not keep then
- kerns,cursives,marks={},{},{}
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
- end
- for n in traverse_id(glyph_code,head) do
- if n.subtype<256 then
- local k=n[a_kernpair]
- if k then
- local kk=kerns[k]
- if kk then
- local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
- if y and y~=0 then
+ end + end + end + end + if not keep then + kerns={} + end + return head,true + elseif not keep then + kerns,cursives,marks={},{},{} + end + elseif has_kerns then + if trace_injections then + trace(head) + end + for n in traverse_id(glyph_code,head) do + if n.subtype<256 then + local k=n[a_kernpair] + if k then + local kk=kerns[k] + if kk then + local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4] + if y and y~=0 then n.yoffset=y - end
+ end if w then - local wx=w-x
+ local wx=w-x if rl<0 then - if wx~=0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x~=0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx~=0 then
- insert_node_after(head,n,newkern(wx))
- end
- end
+ if wx~=0 then + insert_node_before(head,n,newkern(wx)) + end + if x~=0 then + insert_node_after (head,n,newkern(x)) + end + else + if x~=0 then + insert_node_before(head,n,newkern(x)) + end + if wx~=0 then + insert_node_after(head,n,newkern(wx)) + end + end else - if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- end
- end
- end
- end
- end
- if not keep then
- kerns={}
- end - return head,true
+ if x~=0 then + insert_node_before(head,n,newkern(x)) + end + end + end + end + end + end + if not keep then + kerns={} + end + return head,true else - end
- return head,false
-end
+ end + return head,false +end end -- closure @@ -10430,834 +10430,834 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-otp']={
- version=1.001,
- comment="companion to font-otf.lua (packing)",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['font-otp']={ + version=1.001, + comment="companion to font-otf.lua (packing)", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local next,type=next,type
-local sort,concat=table.sort,table.concat
+local next,type=next,type +local sort,concat=table.sort,table.concat local sortedhash=table.sortedhash -local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end)
+local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end) local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) local report_otf=logs.reporter("fonts","otf loading") fonts=fonts or {} -local handlers=fonts.handlers or {}
+local handlers=fonts.handlers or {} fonts.handlers=handlers -local otf=handlers.otf or {}
+local otf=handlers.otf or {} handlers.otf=otf -local enhancers=otf.enhancers or {}
+local enhancers=otf.enhancers or {} otf.enhancers=enhancers -local glists=otf.glists or { "gsub","gpos" }
+local glists=otf.glists or { "gsub","gpos" } otf.glists=glists -local criterium=1
+local criterium=1 local threshold=0 -local function tabstr_normal(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- if type(v)=="table" then
- s[n]=k..">"..tabstr_normal(v)
- elseif v==true then
+local function tabstr_normal(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + if type(v)=="table" then + s[n]=k..">"..tabstr_normal(v) + elseif v==true then s[n]=k.."+" - elseif v then
- s[n]=k.."="..v
- else
+ elseif v then + s[n]=k.."="..v + else s[n]=k.."-" - end
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
+ end + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else sort(s) - return concat(s,",")
- end
-end -local function tabstr_flat(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- s[n]=k.."="..v
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
+ return concat(s,",") + end +end +local function tabstr_flat(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + s[n]=k.."="..v + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else sort(s) - return concat(s,",")
- end
+ return concat(s,",") + end end local function tabstr_mixed(t) - local s={}
- local n=#t
- if n==0 then
- return ""
- elseif n==1 then
- local k=t[1]
- if k==true then
+ local s={} + local n=#t + if n==0 then + return "" + elseif n==1 then + local k=t[1] + if k==true then return "++" - elseif k==false then
+ elseif k==false then return "--" - else
+ else return tostring(k) - end
- else
- for i=1,n do
- local k=t[i]
- if k==true then
+ end + else + for i=1,n do + local k=t[i] + if k==true then s[i]="++" - elseif k==false then
+ elseif k==false then s[i]="--" - else
+ else s[i]=k - end
- end
- return concat(s,",")
- end
-end -local function tabstr_boolean(t)
- local s={}
- local n=0
- for k,v in next,t do
- n=n+1
- if v then
- s[n]=k.."+"
- else
- s[n]=k.."-"
- end
- end
- if n==0 then
- return ""
- elseif n==1 then
- return s[1]
- else
+ end + end + return concat(s,",") + end +end +local function tabstr_boolean(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + if v then + s[n]=k.."+" + else + s[n]=k.."-" + end + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else sort(s) - return concat(s,",")
- end
+ return concat(s,",") + end end -local function packdata(data)
+local function packdata(data) if data then - local h,t,c={},{},{}
- local hh,tt,cc={},{},{}
- local nt,ntt=0,0
- local function pack_normal(v)
- local tag=tabstr_normal(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_flat(v)
- local tag=tabstr_flat(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_boolean(v)
- local tag=tabstr_boolean(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_indexed(v)
- local tag=concat(v," ")
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
- local function pack_mixed(v)
- local tag=tabstr_mixed(v)
- local ht=h[tag]
- if ht then
- c[ht]=c[ht]+1
- return ht
- else
- nt=nt+1
- t[nt]=v
- h[tag]=nt
- c[nt]=1
- return nt
- end
- end
+ local h,t,c={},{},{} + local hh,tt,cc={},{},{} + local nt,ntt=0,0 + local function pack_normal(v) + local tag=tabstr_normal(v) + local ht=h[tag] + if ht then + c[ht]=c[ht]+1 + return ht + else + nt=nt+1 + t[nt]=v + h[tag]=nt + c[nt]=1 + return nt + end + end + local function pack_flat(v) + local tag=tabstr_flat(v) + local ht=h[tag] + if ht then + c[ht]=c[ht]+1 + return ht + else + nt=nt+1 + t[nt]=v + h[tag]=nt + c[nt]=1 + return nt + end + end + local function pack_boolean(v) + local tag=tabstr_boolean(v) + local ht=h[tag] + if ht then + c[ht]=c[ht]+1 + return ht + else + nt=nt+1 + t[nt]=v + h[tag]=nt + c[nt]=1 + return nt + end + end + local function pack_indexed(v) + local tag=concat(v," ") + local ht=h[tag] + if ht then + c[ht]=c[ht]+1 + return ht + else + nt=nt+1 + t[nt]=v + h[tag]=nt + c[nt]=1 + return nt + end + end + local function pack_mixed(v) + local tag=tabstr_mixed(v) + local ht=h[tag] + if ht then + c[ht]=c[ht]+1 + return ht + else + nt=nt+1 + t[nt]=v + h[tag]=nt + c[nt]=1 + return nt + end + end local function pack_final(v) - if c[v]<=criterium then
- return t[v]
+ if c[v]<=criterium then + return t[v] else - local hv=hh[v]
- if hv then
- return hv
- else
- ntt=ntt+1
- tt[ntt]=t[v]
- hh[v]=ntt
- cc[ntt]=c[v]
- return ntt
- end
- end
- end
- local function success(stage,pass)
- if nt==0 then
- if trace_loading or trace_packing then
- report_otf("pack quality: nothing to pack")
- end
- return false
- elseif nt>=threshold then
- local one,two,rest=0,0,0
- if pass==1 then
- for k,v in next,c do
- if v==1 then
- one=one+1
- elseif v==2 then
- two=two+1
- else
- rest=rest+1
- end
- end
- else
- for k,v in next,cc do
- if v>20 then
- rest=rest+1
- elseif v>10 then
- two=two+1
- else
- one=one+1
- end
- end
- data.tables=tt
- end
- if trace_loading or trace_packing then
- report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",stage,pass,one+two+rest,one,two,rest,criterium)
- end
- return true
- else
- if trace_loading or trace_packing then
- report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",stage,pass,nt,threshold)
- end
- return false
- end
- end
- local function packers(pass)
- if pass==1 then
- return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed
- else
- return pack_final,pack_final,pack_final,pack_final,pack_final
- end
- end
- local resources=data.resources
- local lookuptypes=resources.lookuptypes
- for pass=1,2 do
- if trace_packing then
- report_otf("start packing: stage 1, pass %s",pass)
- end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
- for unicode,description in next,data.descriptions do
- local boundingbox=description.boundingbox
- if boundingbox then
- description.boundingbox=pack_indexed(boundingbox)
- end
- local slookups=description.slookups
- if slookups then
- for tag,slookup in next,slookups do
- local what=lookuptypes[tag]
- if what=="pair" then
- local t=slookup[2] if t then slookup[2]=pack_indexed(t) end
- local t=slookup[3] if t then slookup[3]=pack_indexed(t) end
- elseif what~="substitution" then
+ local hv=hh[v] + if hv then + return hv + else + ntt=ntt+1 + tt[ntt]=t[v] + hh[v]=ntt + cc[ntt]=c[v] + return ntt + end + end + end + local function success(stage,pass) + if nt==0 then + if trace_loading or trace_packing then + report_otf("pack quality: nothing to pack") + end + return false + elseif nt>=threshold then + local one,two,rest=0,0,0 + if pass==1 then + for k,v in next,c do + if v==1 then + one=one+1 + elseif v==2 then + two=two+1 + else + rest=rest+1 + end + end + else + for k,v in next,cc do + if v>20 then + rest=rest+1 + elseif v>10 then + two=two+1 + else + one=one+1 + end + end + data.tables=tt + end + if trace_loading or trace_packing then + report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",stage,pass,one+two+rest,one,two,rest,criterium) + end + return true + else + if trace_loading or trace_packing then + report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",stage,pass,nt,threshold) + end + return false + end + end + local function packers(pass) + if pass==1 then + return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed + else + return pack_final,pack_final,pack_final,pack_final,pack_final + end + end + local resources=data.resources + local lookuptypes=resources.lookuptypes + for pass=1,2 do + if trace_packing then + report_otf("start packing: stage 1, pass %s",pass) + end + local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass) + for unicode,description in next,data.descriptions do + local boundingbox=description.boundingbox + if boundingbox then + description.boundingbox=pack_indexed(boundingbox) + end + local slookups=description.slookups + if slookups then + for tag,slookup in next,slookups do + local what=lookuptypes[tag] + if what=="pair" then + local t=slookup[2] if t then slookup[2]=pack_indexed(t) end + local t=slookup[3] if t then slookup[3]=pack_indexed(t) end + elseif what~="substitution" then slookups[tag]=pack_indexed(slookup) - end
- end
- end
- local mlookups=description.mlookups
- if mlookups then
- for tag,mlookup in next,mlookups do
- local what=lookuptypes[tag]
- if what=="pair" then
- for i=1,#mlookup do
- local lookup=mlookup[i]
- local t=lookup[2] if t then lookup[2]=pack_indexed(t) end
- local t=lookup[3] if t then lookup[3]=pack_indexed(t) end
- end
- elseif what~="substitution" then
- for i=1,#mlookup do
+ end + end + end + local mlookups=description.mlookups + if mlookups then + for tag,mlookup in next,mlookups do + local what=lookuptypes[tag] + if what=="pair" then + for i=1,#mlookup do + local lookup=mlookup[i] + local t=lookup[2] if t then lookup[2]=pack_indexed(t) end + local t=lookup[3] if t then lookup[3]=pack_indexed(t) end + end + elseif what~="substitution" then + for i=1,#mlookup do mlookup[i]=pack_indexed(mlookup[i]) - end
- end
- end
- end
- local kerns=description.kerns
- if kerns then
- for tag,kern in next,kerns do
- kerns[tag]=pack_flat(kern)
- end
- end
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- for tag,kern in next,kerns do
- kerns[tag]=pack_normal(kern)
- end
- end
- end
- local anchors=description.anchors
- if anchors then
- for what,anchor in next,anchors do
- if what=="baselig" then
- for _,a in next,anchor do
- for k=1,#a do
- a[k]=pack_indexed(a[k])
- end
- end
- else
- for k,v in next,anchor do
- anchor[k]=pack_indexed(v)
- end
- end
- end
- end
- local altuni=description.altuni
- if altuni then
- for i=1,#altuni do
- altuni[i]=pack_flat(altuni[i])
- end
- end
- end
- local lookups=data.lookups
- if lookups then
- for _,lookup in next,lookups do
- local rules=lookup.rules
- if rules then
- for i=1,#rules do
- local rule=rules[i]
- local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
+ end + end + end + end + local kerns=description.kerns + if kerns then + for tag,kern in next,kerns do + kerns[tag]=pack_flat(kern) + end + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + for tag,kern in next,kerns do + kerns[tag]=pack_normal(kern) + end + end + end + local anchors=description.anchors + if anchors then + for what,anchor in next,anchors do + if what=="baselig" then + for _,a in next,anchor do + for k=1,#a do + a[k]=pack_indexed(a[k]) + end + end + else + for k,v in next,anchor do + anchor[k]=pack_indexed(v) + end + end + end + end + local altuni=description.altuni + if altuni then + for i=1,#altuni do + altuni[i]=pack_flat(altuni[i]) + end + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.rules + if rules then + for i=1,#rules do + local rule=rules[i] + local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end + local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end + local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end local r=rule.replacements if r then rule.replacements=pack_flat (r) end local r=rule.lookups if r then rule.lookups=pack_indexed(r) end - end
- end
- end
- end
- local anchor_to_lookup=resources.anchor_to_lookup
- if anchor_to_lookup then
- for anchor,lookup in next,anchor_to_lookup do
- anchor_to_lookup[anchor]=pack_normal(lookup)
- end
- end
- local lookup_to_anchor=resources.lookup_to_anchor
- if lookup_to_anchor then
- for lookup,anchor in next,lookup_to_anchor do
- lookup_to_anchor[lookup]=pack_normal(anchor)
- end
- end
- local sequences=resources.sequences
- if sequences then
- for feature,sequence in next,sequences do
- local flags=sequence.flags
- if flags then
- sequence.flags=pack_normal(flags)
- end
- local subtables=sequence.subtables
- if subtables then
- sequence.subtables=pack_normal(subtables)
- end
- local features=sequence.features
- if features then
- for script,feature in next,features do
- features[script]=pack_normal(feature)
- end
- end
- end
- end
- local lookups=resources.lookups
- if lookups then
- for name,lookup in next,lookups do
- local flags=lookup.flags
- if flags then
- lookup.flags=pack_normal(flags)
- end
- local subtables=lookup.subtables
- if subtables then
- lookup.subtables=pack_normal(subtables)
- end
- end
- end
- local features=resources.features
- if features then
- for _,what in next,glists do
- local list=features[what]
- if list then
- for feature,spec in next,list do
- list[feature]=pack_normal(spec)
- end
- end
- end
- end
- if not success(1,pass) then
- return
- end
- end
- if nt>0 then
- for pass=1,2 do
- if trace_packing then
- report_otf("start packing: stage 2, pass %s",pass)
- end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
- for unicode,description in next,data.descriptions do
- local kerns=description.kerns
- if kerns then
- description.kerns=pack_normal(kerns)
- end
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- math.kerns=pack_normal(kerns)
- end
- end
- local anchors=description.anchors
- if anchors then
- description.anchors=pack_normal(anchors)
- end
- local mlookups=description.mlookups
- if mlookups then
- for tag,mlookup in next,mlookups do
- mlookups[tag]=pack_normal(mlookup)
- end
- end
- local altuni=description.altuni
- if altuni then
- description.altuni=pack_normal(altuni)
- end
- end
- local lookups=data.lookups
- if lookups then
- for _,lookup in next,lookups do
- local rules=lookup.rules
- if rules then
+ end + end + end + end + local anchor_to_lookup=resources.anchor_to_lookup + if anchor_to_lookup then + for anchor,lookup in next,anchor_to_lookup do + anchor_to_lookup[anchor]=pack_normal(lookup) + end + end + local lookup_to_anchor=resources.lookup_to_anchor + if lookup_to_anchor then + for lookup,anchor in next,lookup_to_anchor do + lookup_to_anchor[lookup]=pack_normal(anchor) + end + end + local sequences=resources.sequences + if sequences then + for feature,sequence in next,sequences do + local flags=sequence.flags + if flags then + sequence.flags=pack_normal(flags) + end + local subtables=sequence.subtables + if subtables then + sequence.subtables=pack_normal(subtables) + end + local features=sequence.features + if features then + for script,feature in next,features do + features[script]=pack_normal(feature) + end + end + end + end + local lookups=resources.lookups + if lookups then + for name,lookup in next,lookups do + local flags=lookup.flags + if flags then + lookup.flags=pack_normal(flags) + end + local subtables=lookup.subtables + if subtables then + lookup.subtables=pack_normal(subtables) + end + end + end + local features=resources.features + if features then + for _,what in next,glists do + local list=features[what] + if list then + for feature,spec in next,list do + list[feature]=pack_normal(spec) + end + end + end + end + if not success(1,pass) then + return + end + end + if nt>0 then + for pass=1,2 do + if trace_packing then + report_otf("start packing: stage 2, pass %s",pass) + end + local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass) + for unicode,description in next,data.descriptions do + local kerns=description.kerns + if kerns then + description.kerns=pack_normal(kerns) + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + math.kerns=pack_normal(kerns) + end + end + local anchors=description.anchors + if anchors then + description.anchors=pack_normal(anchors) + end + local mlookups=description.mlookups + if mlookups then + for tag,mlookup in next,mlookups do + mlookups[tag]=pack_normal(mlookup) + end + end + local altuni=description.altuni + if altuni then + description.altuni=pack_normal(altuni) + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.rules + if rules then for i=1,#rules do - local rule=rules[i]
- local r=rule.before if r then rule.before=pack_normal(r) end
- local r=rule.after if r then rule.after=pack_normal(r) end
- local r=rule.current if r then rule.current=pack_normal(r) end
- end
- end
- end
- end
- local sequences=resources.sequences
- if sequences then
- for feature,sequence in next,sequences do
- sequence.features=pack_normal(sequence.features)
- end
- end
+ local rule=rules[i] + local r=rule.before if r then rule.before=pack_normal(r) end + local r=rule.after if r then rule.after=pack_normal(r) end + local r=rule.current if r then rule.current=pack_normal(r) end + end + end + end + end + local sequences=resources.sequences + if sequences then + for feature,sequence in next,sequences do + sequence.features=pack_normal(sequence.features) + end + end if not success(2,pass) then - end
- end - for pass=1,2 do
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
- for unicode,description in next,data.descriptions do
- local slookups=description.slookups
- if slookups then
- description.slookups=pack_normal(slookups)
- end
- local mlookups=description.mlookups
- if mlookups then
- description.mlookups=pack_normal(mlookups)
- end
- end
- end - end
- end
-end -local unpacked_mt={
- __index=function(t,k)
- t[k]=false
+ end + end + for pass=1,2 do + local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass) + for unicode,description in next,data.descriptions do + local slookups=description.slookups + if slookups then + description.slookups=pack_normal(slookups) + end + local mlookups=description.mlookups + if mlookups then + description.mlookups=pack_normal(mlookups) + end + end + end + end + end +end +local unpacked_mt={ + __index=function(t,k) + t[k]=false return k - end
+ end } -local function unpackdata(data)
- if data then
- local tables=data.tables
- if tables then
- local resources=data.resources
- local lookuptypes=resources.lookuptypes
- local unpacked={}
- setmetatable(unpacked,unpacked_mt)
- for unicode,description in next,data.descriptions do
- local tv=tables[description.boundingbox]
- if tv then
- description.boundingbox=tv
- end
- local slookups=description.slookups
- if slookups then
- local tv=tables[slookups]
- if tv then
- description.slookups=tv
- slookups=unpacked[tv]
- end
- if slookups then
- for tag,lookup in next,slookups do
- local what=lookuptypes[tag]
- if what=="pair" then
- local tv=tables[lookup[2]]
- if tv then
- lookup[2]=tv
- end
- local tv=tables[lookup[3]]
- if tv then
- lookup[3]=tv
- end
- elseif what~="substitution" then
- local tv=tables[lookup]
- if tv then
- slookups[tag]=tv
- end
- end
- end
- end
- end
- local mlookups=description.mlookups
- if mlookups then
- local tv=tables[mlookups]
- if tv then
- description.mlookups=tv
- mlookups=unpacked[tv]
- end
- if mlookups then
- for tag,list in next,mlookups do
- local tv=tables[list]
- if tv then
- mlookups[tag]=tv
- list=unpacked[tv]
- end
- if list then
- local what=lookuptypes[tag]
- if what=="pair" then
- for i=1,#list do
- local lookup=list[i]
- local tv=tables[lookup[2]]
- if tv then
- lookup[2]=tv
- end
- local tv=tables[lookup[3]]
- if tv then
- lookup[3]=tv
- end
- end
- elseif what~="substitution" then
- for i=1,#list do
- local tv=tables[list[i]]
- if tv then
- list[i]=tv
- end
- end
- end
- end
- end
- end
- end
- local kerns=description.kerns
- if kerns then
- local tm=tables[kerns]
- if tm then
- description.kerns=tm
- kerns=unpacked[tm]
- end
- if kerns then
- for k,kern in next,kerns do
- local tv=tables[kern]
- if tv then
- kerns[k]=tv
- end
- end
- end
- end
- local math=description.math
- if math then
- local kerns=math.kerns
- if kerns then
- local tm=tables[kerns]
- if tm then
- math.kerns=tm
- kerns=unpacked[tm]
- end
- if kerns then
- for k,kern in next,kerns do
- local tv=tables[kern]
- if tv then
- kerns[k]=tv
- end
- end
- end
- end
- end
- local anchors=description.anchors
- if anchors then
- local ta=tables[anchors]
- if ta then
- description.anchors=ta
- anchors=unpacked[ta]
- end
- if anchors then
- for tag,anchor in next,anchors do
- if tag=="baselig" then
- for _,list in next,anchor do
- for i=1,#list do
- local tv=tables[list[i]]
- if tv then
- list[i]=tv
- end
- end
- end
- else
- for a,data in next,anchor do
- local tv=tables[data]
- if tv then
- anchor[a]=tv
- end
- end
- end
- end
- end
- end
- local altuni=description.altuni
- if altuni then
- local altuni=tables[altuni]
- if altuni then
- description.altuni=altuni
- for i=1,#altuni do
- local tv=tables[altuni[i]]
- if tv then
- altuni[i]=tv
- end
- end
- end
- end
- end
- local lookups=data.lookups
- if lookups then
- for _,lookup in next,lookups do
- local rules=lookup.rules
- if rules then
+local function unpackdata(data) + if data then + local tables=data.tables + if tables then + local resources=data.resources + local lookuptypes=resources.lookuptypes + local unpacked={} + setmetatable(unpacked,unpacked_mt) + for unicode,description in next,data.descriptions do + local tv=tables[description.boundingbox] + if tv then + description.boundingbox=tv + end + local slookups=description.slookups + if slookups then + local tv=tables[slookups] + if tv then + description.slookups=tv + slookups=unpacked[tv] + end + if slookups then + for tag,lookup in next,slookups do + local what=lookuptypes[tag] + if what=="pair" then + local tv=tables[lookup[2]] + if tv then + lookup[2]=tv + end + local tv=tables[lookup[3]] + if tv then + lookup[3]=tv + end + elseif what~="substitution" then + local tv=tables[lookup] + if tv then + slookups[tag]=tv + end + end + end + end + end + local mlookups=description.mlookups + if mlookups then + local tv=tables[mlookups] + if tv then + description.mlookups=tv + mlookups=unpacked[tv] + end + if mlookups then + for tag,list in next,mlookups do + local tv=tables[list] + if tv then + mlookups[tag]=tv + list=unpacked[tv] + end + if list then + local what=lookuptypes[tag] + if what=="pair" then + for i=1,#list do + local lookup=list[i] + local tv=tables[lookup[2]] + if tv then + lookup[2]=tv + end + local tv=tables[lookup[3]] + if tv then + lookup[3]=tv + end + end + elseif what~="substitution" then + for i=1,#list do + local tv=tables[list[i]] + if tv then + list[i]=tv + end + end + end + end + end + end + end + local kerns=description.kerns + if kerns then + local tm=tables[kerns] + if tm then + description.kerns=tm + kerns=unpacked[tm] + end + if kerns then + for k,kern in next,kerns do + local tv=tables[kern] + if tv then + kerns[k]=tv + end + end + end + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + local tm=tables[kerns] + if tm then + math.kerns=tm + kerns=unpacked[tm] + end + if kerns then + for k,kern in next,kerns do + local tv=tables[kern] + if tv then + kerns[k]=tv + end + end + end + end + end + local anchors=description.anchors + if anchors then + local ta=tables[anchors] + if ta then + description.anchors=ta + anchors=unpacked[ta] + end + if anchors then + for tag,anchor in next,anchors do + if tag=="baselig" then + for _,list in next,anchor do + for i=1,#list do + local tv=tables[list[i]] + if tv then + list[i]=tv + end + end + end + else + for a,data in next,anchor do + local tv=tables[data] + if tv then + anchor[a]=tv + end + end + end + end + end + end + local altuni=description.altuni + if altuni then + local altuni=tables[altuni] + if altuni then + description.altuni=altuni + for i=1,#altuni do + local tv=tables[altuni[i]] + if tv then + altuni[i]=tv + end + end + end + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.rules + if rules then for i=1,#rules do - local rule=rules[i]
- local before=rule.before
- if before then
- local tv=tables[before]
- if tv then
- rule.before=tv
- before=unpacked[tv]
- end
- if before then
- for i=1,#before do
- local tv=tables[before[i]]
- if tv then
- before[i]=tv
- end
- end
- end
- end
- local after=rule.after
- if after then
- local tv=tables[after]
- if tv then
- rule.after=tv
- after=unpacked[tv]
- end
- if after then
- for i=1,#after do
- local tv=tables[after[i]]
- if tv then
- after[i]=tv
- end
- end
- end
- end
- local current=rule.current
- if current then
- local tv=tables[current]
- if tv then
- rule.current=tv
- current=unpacked[tv]
- end
- if current then
- for i=1,#current do
- local tv=tables[current[i]]
- if tv then
- current[i]=tv
- end
- end
- end
- end
- local replacements=rule.replacements
- if replacements then
- local tv=tables[replacements]
- if tv then
- rule.replacements=tv
- end
- end
- local fore=rule.fore
- if fore then
- local tv=tables[fore]
- if tv then
- rule.fore=tv
- end
- end
- local back=rule.back
- if back then
- local tv=tables[back]
- if tv then
- rule.back=tv
- end
- end
- local names=rule.names
- if names then
- local tv=tables[names]
- if tv then
- rule.names=tv
- end
- end
- local lookups=rule.lookups
- if lookups then
- local tv=tables[lookups]
- if tv then
- rule.lookups=tv
- end
- end
- end
- end
- end
- end
- local anchor_to_lookup=resources.anchor_to_lookup
- if anchor_to_lookup then
- for anchor,lookup in next,anchor_to_lookup do
- local tv=tables[lookup]
- if tv then
- anchor_to_lookup[anchor]=tv
- end
- end
- end
- local lookup_to_anchor=resources.lookup_to_anchor
- if lookup_to_anchor then
- for lookup,anchor in next,lookup_to_anchor do
- local tv=tables[anchor]
- if tv then
- lookup_to_anchor[lookup]=tv
- end
- end
- end
- local ls=resources.sequences
- if ls then
- for _,feature in next,ls do
- local flags=feature.flags
- if flags then
- local tv=tables[flags]
- if tv then
- feature.flags=tv
- end
- end
- local subtables=feature.subtables
- if subtables then
- local tv=tables[subtables]
- if tv then
- feature.subtables=tv
- end
- end
- local features=feature.features
- if features then
- local tv=tables[features]
- if tv then
- feature.features=tv
- features=unpacked[tv]
- end
- if features then
- for script,data in next,features do
- local tv=tables[data]
- if tv then
- features[script]=tv
- end
- end
- end
- end
- end
- end
- local lookups=resources.lookups
- if lookups then
- for _,lookup in next,lookups do
- local flags=lookup.flags
- if flags then
- local tv=tables[flags]
- if tv then
- lookup.flags=tv
- end
- end
- local subtables=lookup.subtables
- if subtables then
- local tv=tables[subtables]
- if tv then
- lookup.subtables=tv
- end
- end
- end
- end
- local features=resources.features
- if features then
- for _,what in next,glists do
- local feature=features[what]
- if feature then
- for tag,spec in next,feature do
- local tv=tables[spec]
- if tv then
- feature[tag]=tv
- end
- end
- end
- end
- end
- data.tables=nil
- end
- end
+ local rule=rules[i] + local before=rule.before + if before then + local tv=tables[before] + if tv then + rule.before=tv + before=unpacked[tv] + end + if before then + for i=1,#before do + local tv=tables[before[i]] + if tv then + before[i]=tv + end + end + end + end + local after=rule.after + if after then + local tv=tables[after] + if tv then + rule.after=tv + after=unpacked[tv] + end + if after then + for i=1,#after do + local tv=tables[after[i]] + if tv then + after[i]=tv + end + end + end + end + local current=rule.current + if current then + local tv=tables[current] + if tv then + rule.current=tv + current=unpacked[tv] + end + if current then + for i=1,#current do + local tv=tables[current[i]] + if tv then + current[i]=tv + end + end + end + end + local replacements=rule.replacements + if replacements then + local tv=tables[replacements] + if tv then + rule.replacements=tv + end + end + local fore=rule.fore + if fore then + local tv=tables[fore] + if tv then + rule.fore=tv + end + end + local back=rule.back + if back then + local tv=tables[back] + if tv then + rule.back=tv + end + end + local names=rule.names + if names then + local tv=tables[names] + if tv then + rule.names=tv + end + end + local lookups=rule.lookups + if lookups then + local tv=tables[lookups] + if tv then + rule.lookups=tv + end + end + end + end + end + end + local anchor_to_lookup=resources.anchor_to_lookup + if anchor_to_lookup then + for anchor,lookup in next,anchor_to_lookup do + local tv=tables[lookup] + if tv then + anchor_to_lookup[anchor]=tv + end + end + end + local lookup_to_anchor=resources.lookup_to_anchor + if lookup_to_anchor then + for lookup,anchor in next,lookup_to_anchor do + local tv=tables[anchor] + if tv then + lookup_to_anchor[lookup]=tv + end + end + end + local ls=resources.sequences + if ls then + for _,feature in next,ls do + local flags=feature.flags + if flags then + local tv=tables[flags] + if tv then + feature.flags=tv + end + end + local subtables=feature.subtables + if subtables then + local tv=tables[subtables] + if tv then + feature.subtables=tv + end + end + local features=feature.features + if features then + local tv=tables[features] + if tv then + feature.features=tv + features=unpacked[tv] + end + if features then + for script,data in next,features do + local tv=tables[data] + if tv then + features[script]=tv + end + end + end + end + end + end + local lookups=resources.lookups + if lookups then + for _,lookup in next,lookups do + local flags=lookup.flags + if flags then + local tv=tables[flags] + if tv then + lookup.flags=tv + end + end + local subtables=lookup.subtables + if subtables then + local tv=tables[subtables] + if tv then + lookup.subtables=tv + end + end + end + end + local features=resources.features + if features then + for _,what in next,glists do + local feature=features[what] + if feature then + for tag,spec in next,feature do + local tv=tables[spec] + if tv then + feature[tag]=tv + end + end + end + end + end + data.tables=nil + end + end end if otf.enhancers.register then - otf.enhancers.register("pack",packdata)
+ otf.enhancers.register("pack",packdata) otf.enhancers.register("unpack",unpackdata) end otf.enhancers.unpack=unpackdata @@ -11266,118 +11266,118 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-lua']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-lua']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
+local fonts=fonts fonts.formats.lua="lua" -function fonts.readers.lua(specification)
- local fullname=specification.filename or ""
- if fullname=="" then
- local forced=specification.forced or ""
- if forced~="" then
- fullname=specification.name.."."..forced
- else
- fullname=specification.name
- end
- end
- local fullname=resolvers.findfile(fullname) or ""
- if fullname~="" then
- local loader=loadfile(fullname)
- loader=loader and loader()
- return loader and loader(specification)
- end
-end
+function fonts.readers.lua(specification) + local fullname=specification.filename or "" + if fullname=="" then + local forced=specification.forced or "" + if forced~="" then + fullname=specification.name.."."..forced + else + fullname=specification.name + end + end + local fullname=resolvers.findfile(fullname) or "" + if fullname~="" then + local loader=loadfile(fullname) + loader=loader and loader() + return loader and loader(specification) + end +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-def']={
- 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"
+if not modules then modules={} end modules ['font-def']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub
-local tostring,next=tostring,next
+local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub +local tostring,next=tostring,next local lpegmatch=lpeg.match local allocate=utilities.storage.allocate -local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
+local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end) local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end) -trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading")
+trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading") trackers.register("fonts.all","fonts.*","otf.*","afm.*","tfm.*") local report_defining=logs.reporter("fonts","defining") -local fonts=fonts
-local fontdata=fonts.hashes.identifiers
-local readers=fonts.readers
-local definers=fonts.definers
-local specifiers=fonts.specifiers
-local constructors=fonts.constructors
+local fonts=fonts +local fontdata=fonts.hashes.identifiers +local readers=fonts.readers +local definers=fonts.definers +local specifiers=fonts.specifiers +local constructors=fonts.constructors local fontgoodies=fonts.goodies readers.sequence=allocate { 'otf','ttf','afm','tfm','lua' } -local variants=allocate()
+local variants=allocate() specifiers.variants=variants definers.methods=definers.methods or {} local internalized=allocate() local lastdefined=nil -local loadedfonts=constructors.loadedfonts
+local loadedfonts=constructors.loadedfonts local designsizes=constructors.designsizes local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end local splitter,splitspecifiers=nil,"" local P,C,S,Cc=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc -local left=P("(")
-local right=P(")")
-local colon=P(":")
+local left=P("(") +local right=P(")") +local colon=P(":") local space=P(" ") definers.defaultlookup="file" local prefixpattern=P(false) -local function addspecifier(symbol)
- splitspecifiers=splitspecifiers..symbol
- local method=S(splitspecifiers)
- local lookup=C(prefixpattern)*colon
- local sub=left*C(P(1-left-right-method)^1)*right
- local specification=C(method)*C(P(1)^1)
- local name=C((1-sub-specification)^1)
- splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc("")))
-end -local function addlookup(str,default)
- prefixpattern=prefixpattern+P(str)
+local function addspecifier(symbol) + splitspecifiers=splitspecifiers..symbol + local method=S(splitspecifiers) + local lookup=C(prefixpattern)*colon + local sub=left*C(P(1-left-right-method)^1)*right + local specification=C(method)*C(P(1)^1) + local name=C((1-sub-specification)^1) + splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc(""))) +end +local function addlookup(str,default) + prefixpattern=prefixpattern+P(str) end definers.addlookup=addlookup -addlookup("file")
-addlookup("name")
+addlookup("file") +addlookup("name") addlookup("spec") -local function getspecification(str)
- return lpegmatch(splitter,str)
+local function getspecification(str) + return lpegmatch(splitter,str) end definers.getspecification=getspecification -function definers.registersplit(symbol,action,verbosename)
- addspecifier(symbol)
- variants[symbol]=action
- if verbosename then
- variants[verbosename]=action
- end
-end -local function makespecification(specification,lookup,name,sub,method,detail,size)
- size=size or 655360
- if not lookup or lookup=="" then
- lookup=definers.defaultlookup
- end
- if trace_defining then
- report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a",
- specification,lookup,name,sub,method,detail)
- end
- local t={
+function definers.registersplit(symbol,action,verbosename) + addspecifier(symbol) + variants[symbol]=action + if verbosename then + variants[verbosename]=action + end +end +local function makespecification(specification,lookup,name,sub,method,detail,size) + size=size or 655360 + if not lookup or lookup=="" then + lookup=definers.defaultlookup + end + if trace_defining then + report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a", + specification,lookup,name,sub,method,detail) + end + local t={ lookup=lookup, specification=specification, size=size, @@ -11388,477 +11388,477 @@ local function makespecification(specification,lookup,name,sub,method,detail,siz resolved="", forced="", features={}, - }
- return t
+ } + return t end definers.makespecification=makespecification function definers.analyze(specification,size) - local lookup,name,sub,method,detail=getspecification(specification or "")
- return makespecification(specification,lookup,name,sub,method,detail,size)
+ local lookup,name,sub,method,detail=getspecification(specification or "") + return makespecification(specification,lookup,name,sub,method,detail,size) end -definers.resolvers=definers.resolvers or {}
+definers.resolvers=definers.resolvers or {} local resolvers=definers.resolvers -function resolvers.file(specification)
+function resolvers.file(specification) local name=resolvefile(specification.name) - local suffix=file.suffix(name)
- if fonts.formats[suffix] then
- specification.forced=suffix
- specification.name=file.removesuffix(name)
- else
+ local suffix=file.suffix(name) + if fonts.formats[suffix] then + specification.forced=suffix + specification.name=file.removesuffix(name) + else specification.name=name - end
+ end end -function resolvers.name(specification)
- local resolve=fonts.names.resolve
- if resolve then
+function resolvers.name(specification) + local resolve=fonts.names.resolve + if resolve then local resolved,sub=resolve(specification.name,specification.sub,specification) - if resolved then
- specification.resolved=resolved
- specification.sub=sub
- local suffix=file.suffix(resolved)
- if fonts.formats[suffix] then
- specification.forced=suffix
- specification.name=file.removesuffix(resolved)
- else
- specification.name=resolved
- end
- end
- else
- resolvers.file(specification)
- end
-end -function resolvers.spec(specification)
- local resolvespec=fonts.names.resolvespec
- if resolvespec then
+ if resolved then + specification.resolved=resolved + specification.sub=sub + local suffix=file.suffix(resolved) + if fonts.formats[suffix] then + specification.forced=suffix + specification.name=file.removesuffix(resolved) + else + specification.name=resolved + end + end + else + resolvers.file(specification) + end +end +function resolvers.spec(specification) + local resolvespec=fonts.names.resolvespec + if resolvespec then local resolved,sub=resolvespec(specification.name,specification.sub,specification) - if resolved then
- specification.resolved=resolved
- specification.sub=sub
- specification.forced=file.suffix(resolved)
- specification.name=file.removesuffix(resolved)
- end
- else
- resolvers.name(specification)
- end
-end -function definers.resolve(specification)
+ if resolved then + specification.resolved=resolved + specification.sub=sub + specification.forced=file.suffix(resolved) + specification.name=file.removesuffix(resolved) + end + else + resolvers.name(specification) + end +end +function definers.resolve(specification) if not specification.resolved or specification.resolved=="" then - local r=resolvers[specification.lookup]
- if r then
- r(specification)
- end
- end
- if specification.forced=="" then
- specification.forced=nil
- else
- specification.forced=specification.forced
- end
- specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification))
- if specification.sub and specification.sub~="" then
- specification.hash=specification.sub..' @ '..specification.hash
- end
- return specification
-end -function definers.applypostprocessors(tfmdata)
- local postprocessors=tfmdata.postprocessors
- if postprocessors then
- local properties=tfmdata.properties
- for i=1,#postprocessors do
+ local r=resolvers[specification.lookup] + if r then + r(specification) + end + end + if specification.forced=="" then + specification.forced=nil + else + specification.forced=specification.forced + end + specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification)) + if specification.sub and specification.sub~="" then + specification.hash=specification.sub..' @ '..specification.hash + end + return specification +end +function definers.applypostprocessors(tfmdata) + local postprocessors=tfmdata.postprocessors + if postprocessors then + local properties=tfmdata.properties + for i=1,#postprocessors do local extrahash=postprocessors[i](tfmdata) if type(extrahash)=="string" and extrahash~="" then - extrahash=gsub(lower(extrahash),"[^a-z]","-")
- properties.fullname=format("%s-%s",properties.fullname,extrahash)
- end
- end
- end
- return tfmdata
-end -local function checkembedding(tfmdata)
- local properties=tfmdata.properties
- local embedding
- if directive_embedall then
- embedding="full"
- elseif properties and properties.filename and constructors.dontembed[properties.filename] then
- embedding="no"
- else
- embedding="subset"
- end
- if properties then
- properties.embedding=embedding
- else
- tfmdata.properties={ embedding=embedding }
- end
- tfmdata.embedding=embedding
-end -function definers.loadfont(specification)
- local hash=constructors.hashinstance(specification)
+ extrahash=gsub(lower(extrahash),"[^a-z]","-") + properties.fullname=format("%s-%s",properties.fullname,extrahash) + end + end + end + return tfmdata +end +local function checkembedding(tfmdata) + local properties=tfmdata.properties + local embedding + if directive_embedall then + embedding="full" + elseif properties and properties.filename and constructors.dontembed[properties.filename] then + embedding="no" + else + embedding="subset" + end + if properties then + properties.embedding=embedding + else + tfmdata.properties={ embedding=embedding } + end + tfmdata.embedding=embedding +end +function definers.loadfont(specification) + local hash=constructors.hashinstance(specification) local tfmdata=loadedfonts[hash] - if not tfmdata then
- local forced=specification.forced or ""
- if forced~="" then
- local reader=readers[lower(forced)]
- tfmdata=reader and reader(specification)
- if not tfmdata then
- report_defining("forced type %a of %a not found",forced,specification.name)
- end
- else
+ if not tfmdata then + local forced=specification.forced or "" + if forced~="" then + local reader=readers[lower(forced)] + tfmdata=reader and reader(specification) + if not tfmdata then + report_defining("forced type %a of %a not found",forced,specification.name) + end + else local sequence=readers.sequence - for s=1,#sequence do
- local reader=sequence[s]
+ for s=1,#sequence do + local reader=sequence[s] if readers[reader] then - if trace_defining then
- report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename)
- end
- tfmdata=readers[reader](specification)
- if tfmdata then
- break
- else
- specification.filename=nil
- end
- end
- end
- end
- if tfmdata then
- tfmdata=definers.applypostprocessors(tfmdata)
+ if trace_defining then + report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename) + end + tfmdata=readers[reader](specification) + if tfmdata then + break + else + specification.filename=nil + end + end + end + end + if tfmdata then + tfmdata=definers.applypostprocessors(tfmdata) checkembedding(tfmdata) - loadedfonts[hash]=tfmdata
- designsizes[specification.hash]=tfmdata.parameters.designsize
- end
- end
- if not tfmdata then
- report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup)
- end
- return tfmdata
+ loadedfonts[hash]=tfmdata + designsizes[specification.hash]=tfmdata.parameters.designsize + end + end + if not tfmdata then + report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup) + end + return tfmdata end function constructors.checkvirtualids() end function constructors.readanddefine(name,size) - local specification=definers.analyze(name,size)
- local method=specification.method
- if method and variants[method] then
- specification=variants[method](specification)
- end
- specification=definers.resolve(specification)
- local hash=constructors.hashinstance(specification)
- local id=definers.registered(hash)
- if not id then
- local tfmdata=definers.loadfont(specification)
- if tfmdata then
- tfmdata.properties.hash=hash
+ local specification=definers.analyze(name,size) + local method=specification.method + if method and variants[method] then + specification=variants[method](specification) + end + specification=definers.resolve(specification) + local hash=constructors.hashinstance(specification) + local id=definers.registered(hash) + if not id then + local tfmdata=definers.loadfont(specification) + if tfmdata then + tfmdata.properties.hash=hash constructors.checkvirtualids(tfmdata) - id=font.define(tfmdata)
- definers.register(tfmdata,id)
- else
+ id=font.define(tfmdata) + definers.register(tfmdata,id) + else id=0 - end
- end
- return fontdata[id],id
+ end + end + return fontdata[id],id end function definers.current() - return lastdefined
-end -function definers.registered(hash)
- local id=internalized[hash]
- return id,id and fontdata[id]
-end -function definers.register(tfmdata,id)
- if tfmdata and id then
- local hash=tfmdata.properties.hash
- if not hash then
- report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?")
- elseif not internalized[hash] then
- internalized[hash]=id
- if trace_defining then
- report_defining("registering font, id %s, hash %a",id,hash)
- end
- fontdata[id]=tfmdata
- end
- end
+ return lastdefined +end +function definers.registered(hash) + local id=internalized[hash] + return id,id and fontdata[id] +end +function definers.register(tfmdata,id) + if tfmdata and id then + local hash=tfmdata.properties.hash + if not hash then + report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?") + elseif not internalized[hash] then + internalized[hash]=id + if trace_defining then + report_defining("registering font, id %s, hash %a",id,hash) + end + fontdata[id]=tfmdata + end + end end function definers.read(specification,size,id) - statistics.starttiming(fonts)
- if type(specification)=="string" then
- specification=definers.analyze(specification,size)
- end
- local method=specification.method
- if method and variants[method] then
- specification=variants[method](specification)
- end
- specification=definers.resolve(specification)
- local hash=constructors.hashinstance(specification)
+ statistics.starttiming(fonts) + if type(specification)=="string" then + specification=definers.analyze(specification,size) + end + local method=specification.method + if method and variants[method] then + specification=variants[method](specification) + end + specification=definers.resolve(specification) + local hash=constructors.hashinstance(specification) local tfmdata=definers.registered(hash) - if tfmdata then
- if trace_defining then
- report_defining("already hashed: %s",hash)
- end
- else
+ if tfmdata then + if trace_defining then + report_defining("already hashed: %s",hash) + end + else tfmdata=definers.loadfont(specification) - if tfmdata then
- if trace_defining then
- report_defining("loaded and hashed: %s",hash)
- end
- tfmdata.properties.hash=hash
- if id then
- definers.register(tfmdata,id)
- end
- else
- if trace_defining then
- report_defining("not loaded and hashed: %s",hash)
- end
- end
- end
+ if tfmdata then + if trace_defining then + report_defining("loaded and hashed: %s",hash) + end + tfmdata.properties.hash=hash + if id then + definers.register(tfmdata,id) + end + else + if trace_defining then + report_defining("not loaded and hashed: %s",hash) + end + end + end lastdefined=tfmdata or id if not tfmdata then - report_defining("unknown font %a, loading aborted",specification.name)
- elseif trace_defining and type(tfmdata)=="table" then
- local properties=tfmdata.properties or {}
- local parameters=tfmdata.parameters or {}
- report_defining("using %s font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
- properties.format,id,properties.name,parameters.size,properties.encodingbytes,
- properties.encodingname,properties.fullname,file.basename(properties.filename))
- end
- statistics.stoptiming(fonts)
- return tfmdata
-end -function font.getfont(id)
+ report_defining("unknown font %a, loading aborted",specification.name) + elseif trace_defining and type(tfmdata)=="table" then + local properties=tfmdata.properties or {} + local parameters=tfmdata.parameters or {} + report_defining("using %s font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a", + properties.format,id,properties.name,parameters.size,properties.encodingbytes, + properties.encodingname,properties.fullname,file.basename(properties.filename)) + end + statistics.stoptiming(fonts) + return tfmdata +end +function font.getfont(id) return fontdata[id] end -callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
+callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-font-def']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-font-def']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end local fonts=fonts fonts.constructors.namemode="specification" -function fonts.definers.getspecification(str)
- return "",str,"",":",str
+function fonts.definers.getspecification(str) + return "",str,"",":",str end local list={} local function issome () list.lookup='name' end -local function isfile () list.lookup='file' end
-local function isname () list.lookup='name' end
-local function thename(s) list.name=s end
-local function issub (v) list.sub=v end
-local function iscrap (s) list.crap=string.lower(s) end
-local function iskey (k,v) list[k]=v end
-local function istrue (s) list[s]=true end
+local function isfile () list.lookup='file' end +local function isname () list.lookup='name' end +local function thename(s) list.name=s end +local function issub (v) list.sub=v end +local function iscrap (s) list.crap=string.lower(s) end +local function iskey (k,v) list[k]=v end +local function istrue (s) list[s]=true end local function isfalse(s) list[s]=false end local P,S,R,C=lpeg.P,lpeg.S,lpeg.R,lpeg.C -local spaces=P(" ")^0
+local spaces=P(" ")^0 local namespec=(1-S("/:("))^0 -local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces
-local filename_1=P("file:")/isfile*(namespec/thename)
-local filename_2=P("[")*P(true)/isname*(((1-P("]"))^0)/thename)*P("]")
-local fontname_1=P("name:")/isname*(namespec/thename)
-local fontname_2=P(true)/issome*(namespec/thename)
-local sometext=(R("az","AZ","09")+S("+-."))^1
-local truevalue=P("+")*spaces*(sometext/istrue)
-local falsevalue=P("-")*spaces*(sometext/isfalse)
-local keyvalue=(C(sometext)*spaces*P("=")*spaces*C(sometext))/iskey
-local somevalue=sometext/istrue
+local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces +local filename_1=P("file:")/isfile*(namespec/thename) +local filename_2=P("[")*P(true)/isname*(((1-P("]"))^0)/thename)*P("]") +local fontname_1=P("name:")/isname*(namespec/thename) +local fontname_2=P(true)/issome*(namespec/thename) +local sometext=(R("az","AZ","09")+S("+-."))^1 +local truevalue=P("+")*spaces*(sometext/istrue) +local falsevalue=P("-")*spaces*(sometext/isfalse) +local keyvalue=(C(sometext)*spaces*P("=")*spaces*C(sometext))/iskey +local somevalue=sometext/istrue local subvalue=P("(")*(C(P(1-S("()"))^1)/issub)*P(")") -local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces
+local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces local options=P(":")*spaces*(P(";")^0*option)^0 local pattern=(filename_1+filename_2+fontname_1+fontname_2)*subvalue^0*crapspec^0*options^0 local function colonized(specification) - list={}
- lpeg.match(pattern,specification.specification)
+ list={} + lpeg.match(pattern,specification.specification) list.crap=nil - if list.name then
- specification.name=list.name
- list.name=nil
- end
- if list.lookup then
- specification.lookup=list.lookup
- list.lookup=nil
- end
- if list.sub then
- specification.sub=list.sub
- list.sub=nil
- end
- specification.features.normal=fonts.handlers.otf.features.normalize(list)
- return specification
-end -fonts.definers.registersplit(":",colonized,"cryptic")
+ if list.name then + specification.name=list.name + list.name=nil + end + if list.lookup then + specification.lookup=list.lookup + list.lookup=nil + end + if list.sub then + specification.sub=list.sub + list.sub=nil + end + specification.features.normal=fonts.handlers.otf.features.normalize(list) + return specification +end +fonts.definers.registersplit(":",colonized,"cryptic") fonts.definers.registersplit("",colonized,"more cryptic") -function fonts.definers.applypostprocessors(tfmdata)
- local postprocessors=tfmdata.postprocessors
- if postprocessors then
- for i=1,#postprocessors do
+function fonts.definers.applypostprocessors(tfmdata) + local postprocessors=tfmdata.postprocessors + if postprocessors then + for i=1,#postprocessors do local extrahash=postprocessors[i](tfmdata) if type(extrahash)=="string" and extrahash~="" then - extrahash=string.gsub(lower(extrahash),"[^a-z]","-")
- tfmdata.properties.fullname=format("%s-%s",tfmdata.properties.fullname,extrahash)
- end
- end
- end
- return tfmdata
-end
+ extrahash=string.gsub(lower(extrahash),"[^a-z]","-") + tfmdata.properties.fullname=format("%s-%s",tfmdata.properties.fullname,extrahash) + end + end + end + return tfmdata +end end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-ext']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-ext']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
+local fonts=fonts local otffeatures=fonts.constructors.newfeatures("otf") -local function initializeitlc(tfmdata,value)
+local function initializeitlc(tfmdata,value) if value then - local parameters=tfmdata.parameters
- local italicangle=parameters.italicangle
- if italicangle and italicangle~=0 then
- local properties=tfmdata.properties
- local factor=tonumber(value) or 1
- properties.hasitalics=true
- properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
- end
- end
-end -otffeatures.register {
- name="itlc",
- description="italic correction",
- initializers={
- base=initializeitlc,
- node=initializeitlc,
- }
+ local parameters=tfmdata.parameters + local italicangle=parameters.italicangle + if italicangle and italicangle~=0 then + local properties=tfmdata.properties + local factor=tonumber(value) or 1 + properties.hasitalics=true + properties.autoitalicamount=factor*(parameters.uwidth or 40)/2 + end + end +end +otffeatures.register { + name="itlc", + description="italic correction", + initializers={ + base=initializeitlc, + node=initializeitlc, + } } -local function initializeslant(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>1 then
- value=1
- elseif value<-1 then
- value=-1
- end
- tfmdata.parameters.slantfactor=value
-end -otffeatures.register {
- name="slant",
- description="slant glyphs",
- initializers={
- base=initializeslant,
- node=initializeslant,
- }
+local function initializeslant(tfmdata,value) + value=tonumber(value) + if not value then + value=0 + elseif value>1 then + value=1 + elseif value<-1 then + value=-1 + end + tfmdata.parameters.slantfactor=value +end +otffeatures.register { + name="slant", + description="slant glyphs", + initializers={ + base=initializeslant, + node=initializeslant, + } } -local function initializeextend(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>10 then
- value=10
- elseif value<-10 then
- value=-10
- end
- tfmdata.parameters.extendfactor=value
-end -otffeatures.register {
- name="extend",
- description="scale glyphs horizontally",
- initializers={
- base=initializeextend,
- node=initializeextend,
- }
+local function initializeextend(tfmdata,value) + value=tonumber(value) + if not value then + value=0 + elseif value>10 then + value=10 + elseif value<-10 then + value=-10 + end + tfmdata.parameters.extendfactor=value +end +otffeatures.register { + name="extend", + description="scale glyphs horizontally", + initializers={ + base=initializeextend, + node=initializeextend, + } } -fonts.protrusions=fonts.protrusions or {}
+fonts.protrusions=fonts.protrusions or {} fonts.protrusions.setups=fonts.protrusions.setups or {} local setups=fonts.protrusions.setups -local function initializeprotrusion(tfmdata,value)
- if value then
- local setup=setups[value]
- if setup then
- local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1
- local emwidth=tfmdata.parameters.quad
- tfmdata.parameters.protrusion={
- auto=true,
- }
- for i,chr in next,tfmdata.characters do
- local v,pl,pr=setup[i],nil,nil
- if v then
- pl,pr=v[1],v[2]
- end
- if pl and pl~=0 then chr.left_protruding=left*pl*factor end
- if pr and pr~=0 then chr.right_protruding=right*pr*factor end
- end
- end
- end
-end -otffeatures.register {
- name="protrusion",
- description="shift characters into the left and or right margin",
- initializers={
- base=initializeprotrusion,
- node=initializeprotrusion,
- }
+local function initializeprotrusion(tfmdata,value) + if value then + local setup=setups[value] + if setup then + local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1 + local emwidth=tfmdata.parameters.quad + tfmdata.parameters.protrusion={ + auto=true, + } + for i,chr in next,tfmdata.characters do + local v,pl,pr=setup[i],nil,nil + if v then + pl,pr=v[1],v[2] + end + if pl and pl~=0 then chr.left_protruding=left*pl*factor end + if pr and pr~=0 then chr.right_protruding=right*pr*factor end + end + end + end +end +otffeatures.register { + name="protrusion", + description="shift characters into the left and or right margin", + initializers={ + base=initializeprotrusion, + node=initializeprotrusion, + } } -fonts.expansions=fonts.expansions or {}
+fonts.expansions=fonts.expansions or {} fonts.expansions.setups=fonts.expansions.setups or {} local setups=fonts.expansions.setups -local function initializeexpansion(tfmdata,value)
- if value then
- local setup=setups[value]
- if setup then
- local factor=setup.factor or 1
- tfmdata.parameters.expansion={
- stretch=10*(setup.stretch or 0),
- shrink=10*(setup.shrink or 0),
- step=10*(setup.step or 0),
- auto=true,
- }
- for i,chr in next,tfmdata.characters do
- local v=setup[i]
- if v and v~=0 then
- chr.expansion_factor=v*factor
+local function initializeexpansion(tfmdata,value) + if value then + local setup=setups[value] + if setup then + local factor=setup.factor or 1 + tfmdata.parameters.expansion={ + stretch=10*(setup.stretch or 0), + shrink=10*(setup.shrink or 0), + step=10*(setup.step or 0), + auto=true, + } + for i,chr in next,tfmdata.characters do + local v=setup[i] + if v and v~=0 then + chr.expansion_factor=v*factor else - chr.expansion_factor=factor
- end
- end
- end
- end
-end -otffeatures.register {
- name="expansion",
- description="apply hz optimization",
- initializers={
- base=initializeexpansion,
- node=initializeexpansion,
- }
+ chr.expansion_factor=factor + end + end + end + end +end +otffeatures.register { + name="expansion", + description="apply hz optimization", + initializers={ + base=initializeexpansion, + node=initializeexpansion, + } } function fonts.loggers.onetimemessage() end local byte=string.byte fonts.expansions.setups['default']={ stretch=2,shrink=2,step=.5,factor=1, - [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
- [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
- [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
- [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
- [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
- [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
- [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
- [byte('w')]=0.7,[byte('z')]=0.7,
- [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
+ [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7, + [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7, + [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7, + [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7, + [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7, + [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7, + [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7, + [byte('w')]=0.7,[byte('z')]=0.7, + [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7, } fonts.protrusions.setups['default']={ factor=1,left=1,right=1, @@ -11875,120 +11875,120 @@ fonts.protrusions.setups['default']={ [0x061B]={ 0,1 }, [0x06D4]={ 0,1 }, } -fonts.handlers.otf.features.normalize=function(t)
- if t.rand then
- t.rand="random"
- end
- return t
-end -function fonts.helpers.nametoslot(name)
- local t=type(name)
- if t=="string" then
- local tfmdata=fonts.hashes.identifiers[currentfont()]
- local shared=tfmdata and tfmdata.shared
- local fntdata=shared and shared.rawdata
- return fntdata and fntdata.resources.unicodes[name]
- elseif t=="number" then
- return n
- end
-end -fonts.encodings=fonts.encodings or {}
-local reencodings={}
+fonts.handlers.otf.features.normalize=function(t) + if t.rand then + t.rand="random" + end + return t +end +function fonts.helpers.nametoslot(name) + local t=type(name) + if t=="string" then + local tfmdata=fonts.hashes.identifiers[currentfont()] + local shared=tfmdata and tfmdata.shared + local fntdata=shared and shared.rawdata + return fntdata and fntdata.resources.unicodes[name] + elseif t=="number" then + return n + end +end +fonts.encodings=fonts.encodings or {} +local reencodings={} fonts.encodings.reencodings=reencodings local function specialreencode(tfmdata,value) - local encoding=value and reencodings[value]
- if encoding then
- local temp={}
- local char=tfmdata.characters
- for k,v in next,encoding do
- temp[k]=char[v]
- end
- for k,v in next,temp do
- char[k]=temp[k]
- end - return string.format("reencoded:%s",value)
- end
-end -local function reencode(tfmdata,value)
- tfmdata.postprocessors=tfmdata.postprocessors or {}
- table.insert(tfmdata.postprocessors,
- function(tfmdata)
- return specialreencode(tfmdata,value)
- end
- )
-end -otffeatures.register {
- name="reencode",
- description="reencode characters",
- manipulators={
- base=reencode,
- node=reencode,
- }
-}
+ local encoding=value and reencodings[value] + if encoding then + local temp={} + local char=tfmdata.characters + for k,v in next,encoding do + temp[k]=char[v] + end + for k,v in next,temp do + char[k]=temp[k] + end + return string.format("reencoded:%s",value) + end +end +local function reencode(tfmdata,value) + tfmdata.postprocessors=tfmdata.postprocessors or {} + table.insert(tfmdata.postprocessors, + function(tfmdata) + return specialreencode(tfmdata,value) + end + ) +end +otffeatures.register { + name="reencode", + description="reencode characters", + manipulators={ + base=reencode, + node=reencode, + } +} end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-fonts-cbk']={
- version=1.001,
- comment="companion to luatex-*.tex",
- author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright="PRAGMA ADE / ConTeXt Development Team",
- license="see context related readme files"
+if not modules then modules={} end modules ['luatex-fonts-cbk']={ + version=1.001, + comment="companion to luatex-*.tex", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() end -local fonts=fonts
+local fonts=fonts local nodes=nodes -local traverse_id=node.traverse_id
+local traverse_id=node.traverse_id local glyph_code=nodes.nodecodes.glyph -function nodes.handlers.characters(head)
- local fontdata=fonts.hashes.identifiers
- if fontdata then
- local usedfonts,done,prevfont={},false,nil
- for n in traverse_id(glyph_code,head) do
- local font=n.font
- if font~=prevfont then
- prevfont=font
- local used=usedfonts[font]
- if not used then
+function nodes.handlers.characters(head) + local fontdata=fonts.hashes.identifiers + if fontdata then + local usedfonts,done,prevfont={},false,nil + for n in traverse_id(glyph_code,head) do + local font=n.font + if font~=prevfont then + prevfont=font + local used=usedfonts[font] + if not used then local tfmdata=fontdata[font] - if tfmdata then
+ if tfmdata then local shared=tfmdata.shared - if shared then
- local processors=shared.processes
- if processors and #processors>0 then
- usedfonts[font]=processors
- done=true
- end
- end
- end
- end
- end
- end
- if done then
- for font,processors in next,usedfonts do
- for i=1,#processors do
- local h,d=processors[i](head,font,0)
- head,done=h or head,done or d
- end
- end
- end
- return head,true
- else
- return head,false
- end
+ if shared then + local processors=shared.processes + if processors and #processors>0 then + usedfonts[font]=processors + done=true + end + end + end + end + end + end + if done then + for font,processors in next,usedfonts do + for i=1,#processors do + local h,d=processors[i](head,font,0) + head,done=h or head,done or d + end + end + end + return head,true + else + return head,false + end end function nodes.simple_font_handler(head) - head=nodes.handlers.characters(head)
- nodes.injections.handler(head)
- nodes.handlers.protectglyphs(head)
- head=node.ligaturing(head)
- head=node.kerning(head)
- return head
-end
+ head=nodes.handlers.characters(head) + nodes.injections.handler(head) + nodes.handlers.protectglyphs(head) + head=node.ligaturing(head) + head=node.kerning(head) + return head +end end -- closure diff --git a/tex/generic/context/luatex/luatex-fonts-syn.lua b/tex/generic/context/luatex/luatex-fonts-syn.lua index 50c43bce7..ea6e3cab5 100644 --- a/tex/generic/context/luatex/luatex-fonts-syn.lua +++ b/tex/generic/context/luatex/luatex-fonts-syn.lua @@ -1,102 +1,102 @@ -if not modules then modules = { } end modules ['luatex-fonts-syn'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
--- Generic font names support.
---
--- Watch out, the version number is the same as the one used in
--- the mtx-fonts.lua function scripts.fonts.names as we use a
--- simplified font database in the plain solution and by using
--- a different number we're less dependent on context.
---
--- mtxrun --script font --reload --simple
---
--- The format of the file is as follows:
---
--- return {
--- ["version"] = 1.001,
--- ["cache_version"] = 1.001,
--- ["mappings"] = {
--- ["somettcfontone"] = { "Some TTC Font One", "SomeFontA.ttc", 1 },
--- ["somettcfonttwo"] = { "Some TTC Font Two", "SomeFontA.ttc", 2 },
--- ["somettffont"] = { "Some TTF Font", "SomeFontB.ttf" },
--- ["someotffont"] = { "Some OTF Font", "SomeFontC.otf" },
--- },
--- }
-
-local fonts = fonts
-fonts.names = fonts.names or { }
-
-fonts.names.version = 1.001 -- not the same as in context but matches mtx-fonts --simple
-fonts.names.basename = "luatex-fonts-names"
-fonts.names.new_to_old = { }
-fonts.names.old_to_new = { }
-fonts.names.cache = containers.define("fonts","data",fonts.names.version,true)
-
-local data, loaded = nil, false
-
-local fileformats = { "lua", "tex", "other text files" }
-
-function fonts.names.reportmissingbase()
- texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>")
- fonts.names.reportmissingbase = nil
-end
-
-function fonts.names.reportmissingname()
- texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>")
- fonts.names.reportmissingname = nil
-end
-
-function fonts.names.resolve(name,sub)
- if not loaded then
- local basename = fonts.names.basename
- if basename and basename ~= "" then
- data = containers.read(fonts.names.cache,basename)
- if not data then
- basename = file.addsuffix(basename,"lua")
- for i=1,#fileformats do
- local format = fileformats[i]
- local foundname = resolvers.findfile(basename,format) or ""
- if foundname ~= "" then
- data = dofile(foundname)
- texio.write("<font database loaded: ",foundname,">")
- break
- end
- end
- end
- end
- loaded = true
- end
- if type(data) == "table" and data.version == fonts.names.version then
- local condensed = string.gsub(string.lower(name),"[^%a%d]","")
- local found = data.mappings and data.mappings[condensed]
- if found then
- local fontname, filename, subfont = found[1], found[2], found[3]
- if subfont then
- return filename, fontname
- else
- return filename, false
- end
- elseif fonts.names.reportmissingname then
- fonts.names.reportmissingname()
- return name, false -- fallback to filename
- end
- elseif fonts.names.reportmissingbase then
- fonts.names.reportmissingbase()
- end
-end
-
-fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
-
-function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv
- return ""
-end
+if not modules then modules = { } end modules ['luatex-fonts-syn'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +-- Generic font names support. +-- +-- Watch out, the version number is the same as the one used in +-- the mtx-fonts.lua function scripts.fonts.names as we use a +-- simplified font database in the plain solution and by using +-- a different number we're less dependent on context. +-- +-- mtxrun --script font --reload --simple +-- +-- The format of the file is as follows: +-- +-- return { +-- ["version"] = 1.001, +-- ["cache_version"] = 1.001, +-- ["mappings"] = { +-- ["somettcfontone"] = { "Some TTC Font One", "SomeFontA.ttc", 1 }, +-- ["somettcfonttwo"] = { "Some TTC Font Two", "SomeFontA.ttc", 2 }, +-- ["somettffont"] = { "Some TTF Font", "SomeFontB.ttf" }, +-- ["someotffont"] = { "Some OTF Font", "SomeFontC.otf" }, +-- }, +-- } + +local fonts = fonts +fonts.names = fonts.names or { } + +fonts.names.version = 1.001 -- not the same as in context but matches mtx-fonts --simple +fonts.names.basename = "luatex-fonts-names" +fonts.names.new_to_old = { } +fonts.names.old_to_new = { } +fonts.names.cache = containers.define("fonts","data",fonts.names.version,true) + +local data, loaded = nil, false + +local fileformats = { "lua", "tex", "other text files" } + +function fonts.names.reportmissingbase() + texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>") + fonts.names.reportmissingbase = nil +end + +function fonts.names.reportmissingname() + texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>") + fonts.names.reportmissingname = nil +end + +function fonts.names.resolve(name,sub) + if not loaded then + local basename = fonts.names.basename + if basename and basename ~= "" then + data = containers.read(fonts.names.cache,basename) + if not data then + basename = file.addsuffix(basename,"lua") + for i=1,#fileformats do + local format = fileformats[i] + local foundname = resolvers.findfile(basename,format) or "" + if foundname ~= "" then + data = dofile(foundname) + texio.write("<font database loaded: ",foundname,">") + break + end + end + end + end + loaded = true + end + if type(data) == "table" and data.version == fonts.names.version then + local condensed = string.gsub(string.lower(name),"[^%a%d]","") + local found = data.mappings and data.mappings[condensed] + if found then + local fontname, filename, subfont = found[1], found[2], found[3] + if subfont then + return filename, fontname + else + return filename, false + end + elseif fonts.names.reportmissingname then + fonts.names.reportmissingname() + return name, false -- fallback to filename + end + elseif fonts.names.reportmissingbase then + fonts.names.reportmissingbase() + end +end + +fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv + +function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv + return "" +end diff --git a/tex/generic/context/luatex/luatex-fonts-tfm.lua b/tex/generic/context/luatex/luatex-fonts-tfm.lua index 3939d8000..b9bb1bd0f 100644 --- a/tex/generic/context/luatex/luatex-fonts-tfm.lua +++ b/tex/generic/context/luatex/luatex-fonts-tfm.lua @@ -1,38 +1,38 @@ -if not modules then modules = { } end modules ['luatex-fonts-tfm'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
-end
-
-local fonts = fonts
-local tfm = { }
-fonts.handlers.tfm = tfm
-fonts.formats.tfm = "type1" -- we need to have at least a value here
-
-function fonts.readers.tfm(specification)
- local fullname = specification.filename or ""
- if fullname == "" then
- local forced = specification.forced or ""
- if forced ~= "" then
- fullname = specification.name .. "." .. forced
- else
- fullname = specification.name
- end
- end
- local foundname = resolvers.findbinfile(fullname, 'tfm') or ""
- if foundname == "" then
- foundname = resolvers.findbinfile(fullname, 'ofm') or ""
- end
- if foundname ~= "" then
- specification.filename = foundname
- specification.format = "ofm"
- return font.read_tfm(specification.filename,specification.size)
- end
-end
+if not modules then modules = { } end modules ['luatex-fonts-tfm'] = { + version = 1.001, + comment = "companion to luatex-*.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if context then + texio.write_nl("fatal error: this module is not for context") + os.exit() +end + +local fonts = fonts +local tfm = { } +fonts.handlers.tfm = tfm +fonts.formats.tfm = "type1" -- we need to have at least a value here + +function fonts.readers.tfm(specification) + local fullname = specification.filename or "" + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + fullname = specification.name .. "." .. forced + else + fullname = specification.name + end + end + local foundname = resolvers.findbinfile(fullname, 'tfm') or "" + if foundname == "" then + foundname = resolvers.findbinfile(fullname, 'ofm') or "" + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "ofm" + return font.read_tfm(specification.filename,specification.size) + end +end diff --git a/tex/generic/context/luatex/luatex-languages.lua b/tex/generic/context/luatex/luatex-languages.lua index f7be83c84..1ea8c1fd1 100644 --- a/tex/generic/context/luatex/luatex-languages.lua +++ b/tex/generic/context/luatex/luatex-languages.lua @@ -1,45 +1,45 @@ -if not modules then modules = { } end modules ['luatex-languages'] = {
- version = 1.001,
- comment = "companion to luatex-languages.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- We borrow from ConTeXt.
-
-languages = languages or { }
-
-local loaded = { }
-
-function languages.loadpatterns(tag)
- if not loaded[tag] then
- loaded[tag] = 0
- local filename = kpse.find_file("lang-" .. tag .. ".lua")
- if filename and filename == "" then
- print("<unknown language file for: " .. tag .. ">")
- else
- local whatever = loadfile(filename)
- if type(whatever) == "function" then
- whatever = whatever()
- if type(whatever) == "table" then
- local characters = whatever.patterns.characters or ""
- local patterns = whatever.patterns.data or ""
- local exceptions = whatever.exceptions.data or ""
- local language = lang.new()
- for b in string.utfvalues(characters) do
- tex.setlccode(b,b)
- end
- lang.patterns(language, patterns)
- lang.hyphenation(language, exceptions)
- loaded[tag] = lang.id(language)
- else
- print("<invalid language table: " .. tag .. ">")
- end
- else
- print("<invalid language file: " .. tag .. ">")
- end
- end
- end
- return loaded[tag]
-end
+if not modules then modules = { } end modules ['luatex-languages'] = { + version = 1.001, + comment = "companion to luatex-languages.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- We borrow from ConTeXt. + +languages = languages or { } + +local loaded = { } + +function languages.loadpatterns(tag) + if not loaded[tag] then + loaded[tag] = 0 + local filename = kpse.find_file("lang-" .. tag .. ".lua") + if filename and filename == "" then + print("<unknown language file for: " .. tag .. ">") + else + local whatever = loadfile(filename) + if type(whatever) == "function" then + whatever = whatever() + if type(whatever) == "table" then + local characters = whatever.patterns.characters or "" + local patterns = whatever.patterns.data or "" + local exceptions = whatever.exceptions.data or "" + local language = lang.new() + for b in string.utfvalues(characters) do + tex.setlccode(b,b) + end + lang.patterns(language, patterns) + lang.hyphenation(language, exceptions) + loaded[tag] = lang.id(language) + else + print("<invalid language table: " .. tag .. ">") + end + else + print("<invalid language file: " .. tag .. ">") + end + end + end + return loaded[tag] +end diff --git a/tex/generic/context/luatex/luatex-math.lua b/tex/generic/context/luatex/luatex-math.lua index 66d712d64..c316182ba 100644 --- a/tex/generic/context/luatex/luatex-math.lua +++ b/tex/generic/context/luatex/luatex-math.lua @@ -1,53 +1,53 @@ -if not modules then modules = { } end modules ['luatex-math'] = {
- version = 1.001,
- comment = "companion to luatex-math.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local gaps = {
- [0x1D455] = 0x0210E,
- [0x1D49D] = 0x0212C,
- [0x1D4A0] = 0x02130,
- [0x1D4A1] = 0x02131,
- [0x1D4A3] = 0x0210B,
- [0x1D4A4] = 0x02110,
- [0x1D4A7] = 0x02112,
- [0x1D4A8] = 0x02133,
- [0x1D4AD] = 0x0211B,
- [0x1D4BA] = 0x0212F,
- [0x1D4BC] = 0x0210A,
- [0x1D4C4] = 0x02134,
- [0x1D506] = 0x0212D,
- [0x1D50B] = 0x0210C,
- [0x1D50C] = 0x02111,
- [0x1D515] = 0x0211C,
- [0x1D51D] = 0x02128,
- [0x1D53A] = 0x02102,
- [0x1D53F] = 0x0210D,
- [0x1D545] = 0x02115,
- [0x1D547] = 0x02119,
- [0x1D548] = 0x0211A,
- [0x1D549] = 0x0211D,
- [0x1D551] = 0x02124,
-}
-
-
-local function fixmath(tfmdata,key,value)
- if value then
- local characters = tfmdata.characters
- for gap, mess in pairs(gaps) do
- characters[gap] = characters[mess]
- end
- end
-end
-
-fonts.handlers.otf.features.register {
- name = "fixmath",
- description = "math font fixing",
- manipulators = {
- base = fixmath,
- node = fixmath,
- }
-}
+if not modules then modules = { } end modules ['luatex-math'] = { + version = 1.001, + comment = "companion to luatex-math.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local gaps = { + [0x1D455] = 0x0210E, + [0x1D49D] = 0x0212C, + [0x1D4A0] = 0x02130, + [0x1D4A1] = 0x02131, + [0x1D4A3] = 0x0210B, + [0x1D4A4] = 0x02110, + [0x1D4A7] = 0x02112, + [0x1D4A8] = 0x02133, + [0x1D4AD] = 0x0211B, + [0x1D4BA] = 0x0212F, + [0x1D4BC] = 0x0210A, + [0x1D4C4] = 0x02134, + [0x1D506] = 0x0212D, + [0x1D50B] = 0x0210C, + [0x1D50C] = 0x02111, + [0x1D515] = 0x0211C, + [0x1D51D] = 0x02128, + [0x1D53A] = 0x02102, + [0x1D53F] = 0x0210D, + [0x1D545] = 0x02115, + [0x1D547] = 0x02119, + [0x1D548] = 0x0211A, + [0x1D549] = 0x0211D, + [0x1D551] = 0x02124, +} + + +local function fixmath(tfmdata,key,value) + if value then + local characters = tfmdata.characters + for gap, mess in pairs(gaps) do + characters[gap] = characters[mess] + end + end +end + +fonts.handlers.otf.features.register { + name = "fixmath", + description = "math font fixing", + manipulators = { + base = fixmath, + node = fixmath, + } +} diff --git a/tex/generic/context/luatex/luatex-mplib.lua b/tex/generic/context/luatex/luatex-mplib.lua index 74f7dbced..c6628acb3 100644 --- a/tex/generic/context/luatex/luatex-mplib.lua +++ b/tex/generic/context/luatex/luatex-mplib.lua @@ -1,491 +1,491 @@ -if not modules then modules = { } end modules ['luatex-mplib'] = {
- version = 1.001,
- comment = "companion to luatex-mplib.tex",
- author = "Hans Hagen & Taco Hoekwater",
- copyright = "ConTeXt Development Team",
- license = "public domain",
-}
-
---[[ldx--
-<p>This module is a stripped down version of libraries that are used
-by <l n='context'/>. It can be used in other macro packages and/or
-serve as an example. Embedding in a macro package is upto others and
-normally boils down to inputting <t>supp-mpl.tex</t>.</p>
---ldx]]--
-
-if metapost and metapost.version then
-
- --[[ldx--
- <p>Let's silently quit and make sure that no one loads it
- manually in <l n='context'/>.</p>
- --ldx]]--
-
-else
-
- local format, concat, abs, match = string.format, table.concat, math.abs, string.match
-
- local mplib = require ('mplib')
- local kpse = require ('kpse')
-
- --[[ldx--
- <p>We create a namespace and some variables to it. If a namespace is
- already defined it wil not be initialized. This permits hooking
- in code beforehand.</p>
-
- <p>We don't make a format automatically. After all, distributions
- might have their own preferences and normally a format (mem) file will
- have some special place in the <l n='tex'/> tree. Also, there can already
- be format files, different memort settings and other nasty pitfalls that
- we don't want to interfere with. If you want, you can define a function
- <t>metapost.make(name,mem_name) that does the job.</t></p>
- --ldx]]--
-
- metapost = metapost or { }
- metapost.version = 1.00
- metapost.showlog = metapost.showlog or false
- metapost.lastlog = ""
-
- --[[ldx--
- <p>A few helpers, taken from <t>l-file.lua</t>.</p>
- --ldx]]--
-
- local file = file or { }
-
- function file.replacesuffix(filename, suffix)
- return (string.gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
- end
-
- function file.stripsuffix(filename)
- return (string.gsub(filename,"%.[%a%d]+$",""))
- end
-
- --[[ldx--
- <p>We use the <l n='kpse'/> library unless a finder is already
- defined.</p>
- --ldx]]--
-
- local mpkpse = kpse.new("luatex","mpost")
-
- metapost.finder = metapost.finder or function(name, mode, ftype)
- if mode == "w" then
- return name
- else
- return mpkpse:find_file(name,ftype)
- end
- end
-
- --[[ldx--
- <p>You can use your own reported if needed, as long as it handles multiple
- arguments and formatted strings.</p>
- --ldx]]--
-
- metapost.report = metapost.report or function(...)
- texio.write(format("<mplib: %s>",format(...)))
- end
-
- --[[ldx--
- <p>The rest of this module is not documented. More info can be found in the
- <l n='luatex'/> manual, articles in user group journals and the files that
- ship with <l n='context'/>.</p>
- --ldx]]--
-
- function metapost.resetlastlog()
- metapost.lastlog = ""
- end
-
- local mplibone = tonumber(mplib.version()) <= 1.50
-
- if mplibone then
-
- metapost.make = metapost.make or function(name,mem_name,dump)
- local t = os.clock()
- local mpx = mplib.new {
- ini_version = true,
- find_file = metapost.finder,
- job_name = file.stripsuffix(name)
- }
- mpx:execute(string.format("input %s ;",name))
- if dump then
- mpx:execute("dump ;")
- metapost.report("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t)
- else
- metapost.report("%s read in %0.3f seconds",name,os.clock()-t)
- end
- return mpx
- end
-
- function metapost.load(name)
- local mem_name = file.replacesuffix(name,"mem")
- local mpx = mplib.new {
- ini_version = false,
- mem_name = mem_name,
- find_file = metapost.finder
- }
- if not mpx and type(metapost.make) == "function" then
- -- when i have time i'll locate the format and dump
- mpx = metapost.make(name,mem_name)
- end
- if mpx then
- metapost.report("using format %s",mem_name,false)
- return mpx, nil
- else
- return nil, { status = 99, error = "out of memory or invalid format" }
- end
- end
-
- else
-
- local preamble = [[
- boolean mplib ; mplib := true ;
- let dump = endinput ;
- input %s ;
- ]]
-
- metapost.make = metapost.make or function()
- end
-
- function metapost.load(name)
- local mpx = mplib.new {
- ini_version = true,
- find_file = metapost.finder,
- }
- local result
- if not mpx then
- result = { status = 99, error = "out of memory"}
- else
- result = mpx:execute(format(preamble, file.replacesuffix(name,"mp")))
- end
- metapost.reporterror(result)
- return mpx, result
- end
-
- end
-
- function metapost.unload(mpx)
- if mpx then
- mpx:finish()
- end
- end
-
- function metapost.reporterror(result)
- if not result then
- metapost.report("mp error: no result object returned")
- elseif result.status > 0 then
- local t, e, l = result.term, result.error, result.log
- if t then
- metapost.report("mp terminal: %s",t)
- end
- if e then
- metapost.report("mp error: %s", e)
- end
- if not t and not e and l then
- metapost.lastlog = metapost.lastlog .. "\n " .. l
- metapost.report("mp log: %s",l)
- else
- metapost.report("mp error: unknown, no error, terminal or log messages")
- end
- else
- return false
- end
- return true
- end
-
- function metapost.process(mpx, data)
- local converted, result = false, {}
- mpx = metapost.load(mpx)
- if mpx and data then
- local result = mpx:execute(data)
- if not result then
- metapost.report("mp error: no result object returned")
- elseif result.status > 0 then
- metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
- elseif metapost.showlog then
- metapost.lastlog = metapost.lastlog .. "\n" .. result.term
- metapost.report("mp info: %s",result.term or "no-term")
- elseif result.fig then
- converted = metapost.convert(result)
- else
- metapost.report("mp error: unknown error, maybe no beginfig/endfig")
- end
- else
- metapost.report("mp error: mem file not found")
- end
- return converted, result
- end
-
- local function getobjects(result,figure,f)
- return figure:objects()
- end
-
- function metapost.convert(result, flusher)
- metapost.flush(result, flusher)
- return true -- done
- end
-
- --[[ldx--
- <p>We removed some message and tracing code. We might even remove the flusher</p>
- --ldx]]--
-
- local function pdf_startfigure(n,llx,lly,urx,ury)
- tex.sprint(format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
- end
-
- local function pdf_stopfigure()
- tex.sprint("\\stopMPLIBtoPDF")
- end
-
- function pdf_literalcode(fmt,...) -- table
- tex.sprint(format("\\MPLIBtoPDF{%s}",format(fmt,...)))
- end
-
- function pdf_textfigure(font,size,text,width,height,depth)
- text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost
- tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-( 7200/ 7227)/65536*depth))
- end
-
- local bend_tolerance = 131/65536
-
- local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
-
- local function pen_characteristics(object)
- local t = mplib.pen_info(object)
- rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
- divider = sx*sy - rx*ry
- return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
- end
-
- local function concat(px, py) -- no tx, ty here
- return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
- end
-
- local function curved(ith,pth)
- local d = pth.left_x - ith.right_x
- if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
- d = pth.left_y - ith.right_y
- if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
- return false
- end
- end
- return true
- end
-
- local function flushnormalpath(path,open)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord)
- elseif curved(ith,pth) then
- pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
- else
- pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord)
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
- else
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
- elseif #path == 1 then
- -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
- return t
- end
-
- local function flushconcatpath(path,open)
- pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord))
- elseif curved(ith,pth) then
- local a, b = concat(ith.right_x,ith.right_y)
- local c, d = concat(pth.left_x,pth.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
- else
- pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord))
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- local a, b = concat(pth.right_x,pth.right_y)
- local c, d = concat(one.left_x,one.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
- else
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
- end
- elseif #path == 1 then
- -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
- end
- return t
- end
-
- --[[ldx--
- <p>Support for specials has been removed.</p>
- --ldx]]--
-
- function metapost.flush(result,flusher)
- if result then
- local figures = result.fig
- if figures then
- for f=1, #figures do
- metapost.report("flushing figure %s",f)
- local figure = figures[f]
- local objects = getobjects(result,figure,f)
- local fignum = tonumber(match(figure:filename(),"([%d]+)$") or figure:charcode() or 0)
- local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- local bbox = figure:boundingbox()
- local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack
- if urx < llx then
- -- invalid
- pdf_startfigure(fignum,0,0,0,0)
- pdf_stopfigure()
- else
- pdf_startfigure(fignum,llx,lly,urx,ury)
- pdf_literalcode("q")
- if objects then
- for o=1,#objects do
- local object = objects[o]
- local objecttype = object.type
- if objecttype == "start_bounds" or objecttype == "stop_bounds" then
- -- skip
- elseif objecttype == "start_clip" then
- pdf_literalcode("q")
- flushnormalpath(object.path,t,false)
- pdf_literalcode("W n")
- elseif objecttype == "stop_clip" then
- pdf_literalcode("Q")
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- elseif objecttype == "special" then
- -- not supported
- elseif objecttype == "text" then
- local ot = object.transform -- 3,4,5,6,1,2
- pdf_literalcode("q %f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2])
- pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
- pdf_literalcode("Q")
- else
- local cs = object.color
- if cs and #cs > 0 then
- pdf_literalcode(metapost.colorconverter(cs))
- end
- local ml = object.miterlimit
- if ml and ml ~= miterlimit then
- miterlimit = ml
- pdf_literalcode("%f M",ml)
- end
- local lj = object.linejoin
- if lj and lj ~= linejoin then
- linejoin = lj
- pdf_literalcode("%i j",lj)
- end
- local lc = object.linecap
- if lc and lc ~= linecap then
- linecap = lc
- pdf_literalcode("%i J",lc)
- end
- local dl = object.dash
- if dl then
- local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
- if d ~= dashed then
- dashed = d
- pdf_literalcode(dashed)
- end
- elseif dashed then
- pdf_literalcode("[] 0 d")
- dashed = false
- end
- local path = object.path
- local transformed, penwidth = false, 1
- local open = path and path[1].left_type and path[#path].right_type
- local pen = object.pen
- if pen then
- if pen.type == 'elliptical' then
- transformed, penwidth = pen_characteristics(object) -- boolean, value
- pdf_literalcode("%f w",penwidth)
- if objecttype == 'fill' then
- objecttype = 'both'
- end
- else -- calculated by mplib itself
- objecttype = 'fill'
- end
- end
- if transformed then
- pdf_literalcode("q")
- end
- if path then
- if transformed then
- flushconcatpath(path,open)
- else
- flushnormalpath(path,open)
- end
- if objecttype == "fill" then
- pdf_literalcode("h f")
- elseif objecttype == "outline" then
- pdf_literalcode((open and "S") or "h S")
- elseif objecttype == "both" then
- pdf_literalcode("h B")
- end
- end
- if transformed then
- pdf_literalcode("Q")
- end
- local path = object.htap
- if path then
- if transformed then
- pdf_literalcode("q")
- end
- if transformed then
- flushconcatpath(path,open)
- else
- flushnormalpath(path,open)
- end
- if objecttype == "fill" then
- pdf_literalcode("h f")
- elseif objecttype == "outline" then
- pdf_literalcode((open and "S") or "h S")
- elseif objecttype == "both" then
- pdf_literalcode("h B")
- end
- if transformed then
- pdf_literalcode("Q")
- end
- end
- if cr then
- pdf_literalcode(cr)
- end
- end
- end
- end
- pdf_literalcode("Q")
- pdf_stopfigure()
- end
- end
- end
- end
- end
-
- function metapost.colorconverter(cr)
- local n = #cr
- if n == 4 then
- local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
- return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G"
- elseif n == 3 then
- local r, g, b = cr[1], cr[2], cr[3]
- return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G"
- else
- local s = cr[1]
- return format("%.3f g %.3f G",s,s), "0 g 0 G"
- end
- end
-
-end
+if not modules then modules = { } end modules ['luatex-mplib'] = { + version = 1.001, + comment = "companion to luatex-mplib.tex", + author = "Hans Hagen & Taco Hoekwater", + copyright = "ConTeXt Development Team", + license = "public domain", +} + +--[[ldx-- +<p>This module is a stripped down version of libraries that are used +by <l n='context'/>. It can be used in other macro packages and/or +serve as an example. Embedding in a macro package is upto others and +normally boils down to inputting <t>supp-mpl.tex</t>.</p> +--ldx]]-- + +if metapost and metapost.version then + + --[[ldx-- + <p>Let's silently quit and make sure that no one loads it + manually in <l n='context'/>.</p> + --ldx]]-- + +else + + local format, concat, abs, match = string.format, table.concat, math.abs, string.match + + local mplib = require ('mplib') + local kpse = require ('kpse') + + --[[ldx-- + <p>We create a namespace and some variables to it. If a namespace is + already defined it wil not be initialized. This permits hooking + in code beforehand.</p> + + <p>We don't make a format automatically. After all, distributions + might have their own preferences and normally a format (mem) file will + have some special place in the <l n='tex'/> tree. Also, there can already + be format files, different memort settings and other nasty pitfalls that + we don't want to interfere with. If you want, you can define a function + <t>metapost.make(name,mem_name) that does the job.</t></p> + --ldx]]-- + + metapost = metapost or { } + metapost.version = 1.00 + metapost.showlog = metapost.showlog or false + metapost.lastlog = "" + + --[[ldx-- + <p>A few helpers, taken from <t>l-file.lua</t>.</p> + --ldx]]-- + + local file = file or { } + + function file.replacesuffix(filename, suffix) + return (string.gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix + end + + function file.stripsuffix(filename) + return (string.gsub(filename,"%.[%a%d]+$","")) + end + + --[[ldx-- + <p>We use the <l n='kpse'/> library unless a finder is already + defined.</p> + --ldx]]-- + + local mpkpse = kpse.new("luatex","mpost") + + metapost.finder = metapost.finder or function(name, mode, ftype) + if mode == "w" then + return name + else + return mpkpse:find_file(name,ftype) + end + end + + --[[ldx-- + <p>You can use your own reported if needed, as long as it handles multiple + arguments and formatted strings.</p> + --ldx]]-- + + metapost.report = metapost.report or function(...) + texio.write(format("<mplib: %s>",format(...))) + end + + --[[ldx-- + <p>The rest of this module is not documented. More info can be found in the + <l n='luatex'/> manual, articles in user group journals and the files that + ship with <l n='context'/>.</p> + --ldx]]-- + + function metapost.resetlastlog() + metapost.lastlog = "" + end + + local mplibone = tonumber(mplib.version()) <= 1.50 + + if mplibone then + + metapost.make = metapost.make or function(name,mem_name,dump) + local t = os.clock() + local mpx = mplib.new { + ini_version = true, + find_file = metapost.finder, + job_name = file.stripsuffix(name) + } + mpx:execute(string.format("input %s ;",name)) + if dump then + mpx:execute("dump ;") + metapost.report("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t) + else + metapost.report("%s read in %0.3f seconds",name,os.clock()-t) + end + return mpx + end + + function metapost.load(name) + local mem_name = file.replacesuffix(name,"mem") + local mpx = mplib.new { + ini_version = false, + mem_name = mem_name, + find_file = metapost.finder + } + if not mpx and type(metapost.make) == "function" then + -- when i have time i'll locate the format and dump + mpx = metapost.make(name,mem_name) + end + if mpx then + metapost.report("using format %s",mem_name,false) + return mpx, nil + else + return nil, { status = 99, error = "out of memory or invalid format" } + end + end + + else + + local preamble = [[ + boolean mplib ; mplib := true ; + let dump = endinput ; + input %s ; + ]] + + metapost.make = metapost.make or function() + end + + function metapost.load(name) + local mpx = mplib.new { + ini_version = true, + find_file = metapost.finder, + } + local result + if not mpx then + result = { status = 99, error = "out of memory"} + else + result = mpx:execute(format(preamble, file.replacesuffix(name,"mp"))) + end + metapost.reporterror(result) + return mpx, result + end + + end + + function metapost.unload(mpx) + if mpx then + mpx:finish() + end + end + + function metapost.reporterror(result) + if not result then + metapost.report("mp error: no result object returned") + elseif result.status > 0 then + local t, e, l = result.term, result.error, result.log + if t then + metapost.report("mp terminal: %s",t) + end + if e then + metapost.report("mp error: %s", e) + end + if not t and not e and l then + metapost.lastlog = metapost.lastlog .. "\n " .. l + metapost.report("mp log: %s",l) + else + metapost.report("mp error: unknown, no error, terminal or log messages") + end + else + return false + end + return true + end + + function metapost.process(mpx, data) + local converted, result = false, {} + mpx = metapost.load(mpx) + if mpx and data then + local result = mpx:execute(data) + if not result then + metapost.report("mp error: no result object returned") + elseif result.status > 0 then + metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) + elseif metapost.showlog then + metapost.lastlog = metapost.lastlog .. "\n" .. result.term + metapost.report("mp info: %s",result.term or "no-term") + elseif result.fig then + converted = metapost.convert(result) + else + metapost.report("mp error: unknown error, maybe no beginfig/endfig") + end + else + metapost.report("mp error: mem file not found") + end + return converted, result + end + + local function getobjects(result,figure,f) + return figure:objects() + end + + function metapost.convert(result, flusher) + metapost.flush(result, flusher) + return true -- done + end + + --[[ldx-- + <p>We removed some message and tracing code. We might even remove the flusher</p> + --ldx]]-- + + local function pdf_startfigure(n,llx,lly,urx,ury) + tex.sprint(format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury)) + end + + local function pdf_stopfigure() + tex.sprint("\\stopMPLIBtoPDF") + end + + function pdf_literalcode(fmt,...) -- table + tex.sprint(format("\\MPLIBtoPDF{%s}",format(fmt,...))) + end + + function pdf_textfigure(font,size,text,width,height,depth) + text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost + tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-( 7200/ 7227)/65536*depth)) + end + + local bend_tolerance = 131/65536 + + local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1 + + local function pen_characteristics(object) + local t = mplib.pen_info(object) + rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty + divider = sx*sy - rx*ry + return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width + end + + local function concat(px, py) -- no tx, ty here + return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider + end + + local function curved(ith,pth) + local d = pth.left_x - ith.right_x + if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then + d = pth.left_y - ith.right_y + if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then + return false + end + end + return true + end + + local function flushnormalpath(path,open) + local pth, ith + for i=1,#path do + pth = path[i] + if not ith then + pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord) + elseif curved(ith,pth) then + pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord) + else + pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord) + end + ith = pth + end + if not open then + local one = path[1] + if curved(pth,one) then + pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord ) + else + pdf_literalcode("%f %f l",one.x_coord,one.y_coord) + end + elseif #path == 1 then + -- special case .. draw point + local one = path[1] + pdf_literalcode("%f %f l",one.x_coord,one.y_coord) + end + return t + end + + local function flushconcatpath(path,open) + pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty) + local pth, ith + for i=1,#path do + pth = path[i] + if not ith then + pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord)) + elseif curved(ith,pth) then + local a, b = concat(ith.right_x,ith.right_y) + local c, d = concat(pth.left_x,pth.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord)) + else + pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord)) + end + ith = pth + end + if not open then + local one = path[1] + if curved(pth,one) then + local a, b = concat(pth.right_x,pth.right_y) + local c, d = concat(one.left_x,one.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord)) + else + pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + end + elseif #path == 1 then + -- special case .. draw point + local one = path[1] + pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + end + return t + end + + --[[ldx-- + <p>Support for specials has been removed.</p> + --ldx]]-- + + function metapost.flush(result,flusher) + if result then + local figures = result.fig + if figures then + for f=1, #figures do + metapost.report("flushing figure %s",f) + local figure = figures[f] + local objects = getobjects(result,figure,f) + local fignum = tonumber(match(figure:filename(),"([%d]+)$") or figure:charcode() or 0) + local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false + local bbox = figure:boundingbox() + local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack + if urx < llx then + -- invalid + pdf_startfigure(fignum,0,0,0,0) + pdf_stopfigure() + else + pdf_startfigure(fignum,llx,lly,urx,ury) + pdf_literalcode("q") + if objects then + for o=1,#objects do + local object = objects[o] + local objecttype = object.type + if objecttype == "start_bounds" or objecttype == "stop_bounds" then + -- skip + elseif objecttype == "start_clip" then + pdf_literalcode("q") + flushnormalpath(object.path,t,false) + pdf_literalcode("W n") + elseif objecttype == "stop_clip" then + pdf_literalcode("Q") + miterlimit, linecap, linejoin, dashed = -1, -1, -1, false + elseif objecttype == "special" then + -- not supported + elseif objecttype == "text" then + local ot = object.transform -- 3,4,5,6,1,2 + pdf_literalcode("q %f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) + pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth) + pdf_literalcode("Q") + else + local cs = object.color + if cs and #cs > 0 then + pdf_literalcode(metapost.colorconverter(cs)) + end + local ml = object.miterlimit + if ml and ml ~= miterlimit then + miterlimit = ml + pdf_literalcode("%f M",ml) + end + local lj = object.linejoin + if lj and lj ~= linejoin then + linejoin = lj + pdf_literalcode("%i j",lj) + end + local lc = object.linecap + if lc and lc ~= linecap then + linecap = lc + pdf_literalcode("%i J",lc) + end + local dl = object.dash + if dl then + local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset) + if d ~= dashed then + dashed = d + pdf_literalcode(dashed) + end + elseif dashed then + pdf_literalcode("[] 0 d") + dashed = false + end + local path = object.path + local transformed, penwidth = false, 1 + local open = path and path[1].left_type and path[#path].right_type + local pen = object.pen + if pen then + if pen.type == 'elliptical' then + transformed, penwidth = pen_characteristics(object) -- boolean, value + pdf_literalcode("%f w",penwidth) + if objecttype == 'fill' then + objecttype = 'both' + end + else -- calculated by mplib itself + objecttype = 'fill' + end + end + if transformed then + pdf_literalcode("q") + end + if path then + if transformed then + flushconcatpath(path,open) + else + flushnormalpath(path,open) + end + if objecttype == "fill" then + pdf_literalcode("h f") + elseif objecttype == "outline" then + pdf_literalcode((open and "S") or "h S") + elseif objecttype == "both" then + pdf_literalcode("h B") + end + end + if transformed then + pdf_literalcode("Q") + end + local path = object.htap + if path then + if transformed then + pdf_literalcode("q") + end + if transformed then + flushconcatpath(path,open) + else + flushnormalpath(path,open) + end + if objecttype == "fill" then + pdf_literalcode("h f") + elseif objecttype == "outline" then + pdf_literalcode((open and "S") or "h S") + elseif objecttype == "both" then + pdf_literalcode("h B") + end + if transformed then + pdf_literalcode("Q") + end + end + if cr then + pdf_literalcode(cr) + end + end + end + end + pdf_literalcode("Q") + pdf_stopfigure() + end + end + end + end + end + + function metapost.colorconverter(cr) + local n = #cr + if n == 4 then + local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" + elseif n == 3 then + local r, g, b = cr[1], cr[2], cr[3] + return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" + else + local s = cr[1] + return format("%.3f g %.3f G",s,s), "0 g 0 G" + end + end + +end diff --git a/tex/generic/context/luatex/luatex-preprocessor.lua b/tex/generic/context/luatex/luatex-preprocessor.lua index 610fe4b4d..8faa0b47e 100644 --- a/tex/generic/context/luatex/luatex-preprocessor.lua +++ b/tex/generic/context/luatex/luatex-preprocessor.lua @@ -1,163 +1,163 @@ -if not modules then modules = { } end modules ['luatex-preprocessor'] = {
- version = 1.001,
- comment = "companion to luatex-preprocessor.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx
-<p>This is a stripped down version of the preprocessor. In
-<l n='context'/> we have a bit more, use a different logger, and
-use a few optimizations. A few examples are shown at the end.</p>
---ldx]]
-
-local rep, sub, gmatch = string.rep, string.sub, string.gmatch
-local insert, remove = table.insert, table.remove
-local setmetatable = setmetatable
-
-local stack, top, n, hashes = { }, nil, 0, { }
-
-local function set(s)
- if top then
- n = n + 1
- if n > 9 then
- texio.write_nl("number of arguments > 9, ignoring: " .. s)
- else
- local ns = #stack
- local h = hashes[ns]
- if not h then
- h = rep("#",ns)
- hashes[ns] = h
- end
- m = h .. n
- top[s] = m
- return m
- end
- end
-end
-
-local function get(s)
- local m = top and top[s] or s
- return m
-end
-
-local function push()
- top = { }
- n = 0
- local s = stack[#stack]
- if s then
- setmetatable(top,{ __index = s })
- end
- insert(stack,top)
-end
-
-local function pop()
- top = remove(stack)
-end
-
-local leftbrace = lpeg.P("{")
-local rightbrace = lpeg.P("}")
-local escape = lpeg.P("\\")
-
-local space = lpeg.P(" ")
-local spaces = space^1
-local newline = lpeg.S("\r\n")
-local nobrace = 1 - leftbrace - rightbrace
-
-local name = lpeg.R("AZ","az")^1
-local longname = (leftbrace/"") * (nobrace^1) * (rightbrace/"")
-local variable = lpeg.P("#") * lpeg.Cs(name + longname)
-local escapedname = escape * name
-local definer = escape * (lpeg.P("def") + lpeg.P("egdx") * lpeg.P("def"))
-local anything = lpeg.P(1)
-local always = lpeg.P(true)
-
-local pushlocal = always / push
-local poplocal = always / pop
-local declaration = variable / set
-local identifier = variable / get
-
-local function matcherror(str,pos)
- texio.write_nl("runaway definition at: " .. sub(str,pos-30,pos))
-end
-
-local parser = lpeg.Cs { "converter",
- definition = pushlocal
- * definer
- * escapedname
- * (declaration + (1-leftbrace))^0
- * lpeg.V("braced")
- * poplocal,
- braced = leftbrace
- * ( lpeg.V("definition")
- + identifier
- + lpeg.V("braced")
- + nobrace
- )^0
- * (rightbrace + lpeg.Cmt(always,matcherror)),
- converter = (lpeg.V("definition") + anything)^1,
-}
-
---[[ldx
-<p>We provide a few commands.</p>
---ldx]]
-
--- local texkpse
-
-local function find_file(...)
- -- texkpse = texkpse or kpse.new("luatex","tex")
- -- return texkpse:find_file(...) or ""
- return kpse.find_file(...) or ""
-end
-
-commands = commands or { }
-
-function commands.preprocessed(str)
- return lpeg.match(parser,str)
-end
-
-function commands.inputpreprocessed(name)
- local name = find_file(name) or ""
- if name ~= "" then
- -- we could use io.loaddata as it's loaded in luatex-plain
- local f = io.open(name,'rb')
- if f then
- texio.write("("..name)
- local d = commands.preprocessed(f:read("*a"))
- if d and d ~= "" then
- texio.write("processed: " .. name)
- for s in gmatch(d,"[^\n\r]+") do
- tex.print(s) -- we do a dumb feedback
- end
- end
- f:close()
- texio.write(")")
- else
- tex.error("preprocessor error, invalid file: " .. name)
- end
- else
- tex.error("preprocessor error, unknown file: " .. name)
- end
-end
-
-function commands.preprocessfile(oldfile,newfile) -- no checking
- if oldfile and oldfile ~= newfile then
- local f = io.open(oldfile,'rb')
- if f then
- local g = io.open(newfile,'wb')
- if g then
- g:write(lpeg.match(parser,f:read("*a") or ""))
- g:close()
- end
- f:close()
- end
- end
-end
-
---~ print(preprocessed([[\def\test#oeps{test:#oeps}]]))
---~ print(preprocessed([[\def\test#oeps{test:#{oeps}}]]))
---~ print(preprocessed([[\def\test#{oeps:1}{test:#{oeps:1}}]]))
---~ print(preprocessed([[\def\test#{oeps}{test:#oeps}]]))
---~ preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]])
---~ print(preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}}]]))
+if not modules then modules = { } end modules ['luatex-preprocessor'] = { + version = 1.001, + comment = "companion to luatex-preprocessor.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ldx +<p>This is a stripped down version of the preprocessor. In +<l n='context'/> we have a bit more, use a different logger, and +use a few optimizations. A few examples are shown at the end.</p> +--ldx]] + +local rep, sub, gmatch = string.rep, string.sub, string.gmatch +local insert, remove = table.insert, table.remove +local setmetatable = setmetatable + +local stack, top, n, hashes = { }, nil, 0, { } + +local function set(s) + if top then + n = n + 1 + if n > 9 then + texio.write_nl("number of arguments > 9, ignoring: " .. s) + else + local ns = #stack + local h = hashes[ns] + if not h then + h = rep("#",ns) + hashes[ns] = h + end + m = h .. n + top[s] = m + return m + end + end +end + +local function get(s) + local m = top and top[s] or s + return m +end + +local function push() + top = { } + n = 0 + local s = stack[#stack] + if s then + setmetatable(top,{ __index = s }) + end + insert(stack,top) +end + +local function pop() + top = remove(stack) +end + +local leftbrace = lpeg.P("{") +local rightbrace = lpeg.P("}") +local escape = lpeg.P("\\") + +local space = lpeg.P(" ") +local spaces = space^1 +local newline = lpeg.S("\r\n") +local nobrace = 1 - leftbrace - rightbrace + +local name = lpeg.R("AZ","az")^1 +local longname = (leftbrace/"") * (nobrace^1) * (rightbrace/"") +local variable = lpeg.P("#") * lpeg.Cs(name + longname) +local escapedname = escape * name +local definer = escape * (lpeg.P("def") + lpeg.P("egdx") * lpeg.P("def")) +local anything = lpeg.P(1) +local always = lpeg.P(true) + +local pushlocal = always / push +local poplocal = always / pop +local declaration = variable / set +local identifier = variable / get + +local function matcherror(str,pos) + texio.write_nl("runaway definition at: " .. sub(str,pos-30,pos)) +end + +local parser = lpeg.Cs { "converter", + definition = pushlocal + * definer + * escapedname + * (declaration + (1-leftbrace))^0 + * lpeg.V("braced") + * poplocal, + braced = leftbrace + * ( lpeg.V("definition") + + identifier + + lpeg.V("braced") + + nobrace + )^0 + * (rightbrace + lpeg.Cmt(always,matcherror)), + converter = (lpeg.V("definition") + anything)^1, +} + +--[[ldx +<p>We provide a few commands.</p> +--ldx]] + +-- local texkpse + +local function find_file(...) + -- texkpse = texkpse or kpse.new("luatex","tex") + -- return texkpse:find_file(...) or "" + return kpse.find_file(...) or "" +end + +commands = commands or { } + +function commands.preprocessed(str) + return lpeg.match(parser,str) +end + +function commands.inputpreprocessed(name) + local name = find_file(name) or "" + if name ~= "" then + -- we could use io.loaddata as it's loaded in luatex-plain + local f = io.open(name,'rb') + if f then + texio.write("("..name) + local d = commands.preprocessed(f:read("*a")) + if d and d ~= "" then + texio.write("processed: " .. name) + for s in gmatch(d,"[^\n\r]+") do + tex.print(s) -- we do a dumb feedback + end + end + f:close() + texio.write(")") + else + tex.error("preprocessor error, invalid file: " .. name) + end + else + tex.error("preprocessor error, unknown file: " .. name) + end +end + +function commands.preprocessfile(oldfile,newfile) -- no checking + if oldfile and oldfile ~= newfile then + local f = io.open(oldfile,'rb') + if f then + local g = io.open(newfile,'wb') + if g then + g:write(lpeg.match(parser,f:read("*a") or "")) + g:close() + end + f:close() + end + end +end + +--~ print(preprocessed([[\def\test#oeps{test:#oeps}]])) +--~ print(preprocessed([[\def\test#oeps{test:#{oeps}}]])) +--~ print(preprocessed([[\def\test#{oeps:1}{test:#{oeps:1}}]])) +--~ print(preprocessed([[\def\test#{oeps}{test:#oeps}]])) +--~ preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]]) +--~ print(preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}}]])) diff --git a/tex/generic/context/luatex/luatex-swiglib-test.lua b/tex/generic/context/luatex/luatex-swiglib-test.lua index 2f4cc57f6..db6a72909 100644 --- a/tex/generic/context/luatex/luatex-swiglib-test.lua +++ b/tex/generic/context/luatex/luatex-swiglib-test.lua @@ -1,25 +1,25 @@ -local gm = swiglib("gmwand.core")
-
-gm.InitializeMagick(".")
-
-local magick_wand = gm.NewMagickWand()
-local drawing_wand = gm.NewDrawingWand()
-
-gm.MagickSetSize(magick_wand,800,600)
-gm.MagickReadImage(magick_wand,"xc:red")
-
-gm.DrawPushGraphicContext(drawing_wand)
-
-gm.DrawSetFillColor(drawing_wand,gm.NewPixelWand())
-
--- gm.DrawSetFont(drawing_wand, kpse.findfile("DejaVuSerifBold.ttf"))
--- gm.DrawSetFontSize(drawing_wand, 96)
--- gm.DrawAnnotation(drawing_wand,300,200, "LuaTeX")
-
-gm.DrawPopGraphicContext(drawing_wand)
-gm.MagickDrawImage(magick_wand,drawing_wand)
-
-gm.MagickWriteImages(magick_wand,"./luatex-swiglib-test.jpg",1)
-
-gm.DestroyDrawingWand(drawing_wand)
-gm.DestroyMagickWand(magick_wand)
+local gm = swiglib("gmwand.core") + +gm.InitializeMagick(".") + +local magick_wand = gm.NewMagickWand() +local drawing_wand = gm.NewDrawingWand() + +gm.MagickSetSize(magick_wand,800,600) +gm.MagickReadImage(magick_wand,"xc:red") + +gm.DrawPushGraphicContext(drawing_wand) + +gm.DrawSetFillColor(drawing_wand,gm.NewPixelWand()) + +-- gm.DrawSetFont(drawing_wand, kpse.findfile("DejaVuSerifBold.ttf")) +-- gm.DrawSetFontSize(drawing_wand, 96) +-- gm.DrawAnnotation(drawing_wand,300,200, "LuaTeX") + +gm.DrawPopGraphicContext(drawing_wand) +gm.MagickDrawImage(magick_wand,drawing_wand) + +gm.MagickWriteImages(magick_wand,"./luatex-swiglib-test.jpg",1) + +gm.DestroyDrawingWand(drawing_wand) +gm.DestroyMagickWand(magick_wand) diff --git a/tex/generic/context/luatex/luatex-swiglib.lua b/tex/generic/context/luatex/luatex-swiglib.lua index 45416eff4..7ffcdc375 100644 --- a/tex/generic/context/luatex/luatex-swiglib.lua +++ b/tex/generic/context/luatex/luatex-swiglib.lua @@ -1,62 +1,62 @@ -if not modules then modules = { } end modules ['luatex-swiglib'] = {
- version = 1.001,
- comment = "companion to luatex-swiglib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local savedrequire = require
-
-local libsuffix = os.type == "windows" and ".dll" or ".so"
-
-function requireswiglib(required,version)
- local library = package.loaded[required]
- if library then
- return library
- else
- local name = string.gsub(required,"%.","/") .. libsuffix
- local list = kpse.show_path("clua")
- for root in string.gmatch(list,"([^;]+)") do
- local full = false
- if type(version) == "string" and version ~= "" then
- full = root .. "/" .. version .. "/" .. name
- full = lfs.isfile(full) and full
- end
- if not full then
- full = root .. "/" .. name
- full = lfs.isfile(full) and full
- end
- if full then
- local path, base = string.match(full,"^(.-)([^\\/]+)" .. libsuffix .."$")
- local savedlibrary = package.loaded[base]
- package.loaded[base] = nil
- local savedpath = lfs.currentdir()
- lfs.chdir(path)
- library = package.loadlib(full,"luaopen_" .. base)
- if type(library) == "function" then
- library = library()
- texio.write("<swiglib: '",required,"' is loaded>")
- end
- lfs.chdir(savedpath)
- package.loaded[base] = savedlibrary
- package.loaded[required] = library
- return library
- end
- end
- texio.write("<swiglib: '",name,"'is not found on '",list,"'")
- end
- texio.write("<swiglib: '",required,"' is not found>")
-end
-
-function require(name)
- if string.find(name,"^swiglib%.") then
- return requireswiglib(name)
- else
- return savedrequire(name)
- end
-end
-
-function swiglib(name,version)
- return requireswiglib("swiglib." .. name,version)
-end
+if not modules then modules = { } end modules ['luatex-swiglib'] = { + version = 1.001, + comment = "companion to luatex-swiglib.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local savedrequire = require + +local libsuffix = os.type == "windows" and ".dll" or ".so" + +function requireswiglib(required,version) + local library = package.loaded[required] + if library then + return library + else + local name = string.gsub(required,"%.","/") .. libsuffix + local list = kpse.show_path("clua") + for root in string.gmatch(list,"([^;]+)") do + local full = false + if type(version) == "string" and version ~= "" then + full = root .. "/" .. version .. "/" .. name + full = lfs.isfile(full) and full + end + if not full then + full = root .. "/" .. name + full = lfs.isfile(full) and full + end + if full then + local path, base = string.match(full,"^(.-)([^\\/]+)" .. libsuffix .."$") + local savedlibrary = package.loaded[base] + package.loaded[base] = nil + local savedpath = lfs.currentdir() + lfs.chdir(path) + library = package.loadlib(full,"luaopen_" .. base) + if type(library) == "function" then + library = library() + texio.write("<swiglib: '",required,"' is loaded>") + end + lfs.chdir(savedpath) + package.loaded[base] = savedlibrary + package.loaded[required] = library + return library + end + end + texio.write("<swiglib: '",name,"'is not found on '",list,"'") + end + texio.write("<swiglib: '",required,"' is not found>") +end + +function require(name) + if string.find(name,"^swiglib%.") then + return requireswiglib(name) + else + return savedrequire(name) + end +end + +function swiglib(name,version) + return requireswiglib("swiglib." .. name,version) +end |