diff options
author | Philipp Gesang <phg@phi-gamma.net> | 2015-06-13 00:40:45 +0200 |
---|---|---|
committer | Philipp Gesang <phg@phi-gamma.net> | 2015-06-13 00:40:45 +0200 |
commit | 90f398e1c9d2896b2d30d0b66f9c8a88255511a8 (patch) | |
tree | 88459ad0c6986a6648c969726081248cd5c8d74e /src/fontloader | |
parent | c4c4901173b0f4284534db1b6a3cfe865b05e15c (diff) | |
parent | b271e253b40cd0af97f6d50f0461f87ad1ed5314 (diff) | |
download | luaotfload-90f398e1c9d2896b2d30d0b66f9c8a88255511a8.tar.gz |
Merge pull request #274 from phi-gamma/master
pull in current state of affairs
Diffstat (limited to 'src/fontloader')
-rw-r--r-- | src/fontloader/luaotfload-package.lua | 96 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-basics.tex | 70 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-con.lua | 22 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-map.lua | 57 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-otf.lua | 376 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-otp.lua | 2 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-fonts-cbk.lua | 42 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-fonts-inj.lua | 11 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-fonts-otn.lua | 33 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-l-lpeg.lua | 236 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-l-math.lua | 4 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-l-table.lua | 280 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-mplib.tex | 1 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-plain.tex | 1 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-util-str.lua | 28 | ||||
-rw-r--r-- | src/fontloader/runtime/fontloader-fontloader.lua | 698 |
16 files changed, 1347 insertions, 610 deletions
diff --git a/src/fontloader/luaotfload-package.lua b/src/fontloader/luaotfload-package.lua new file mode 100644 index 0000000..b60ae17 --- /dev/null +++ b/src/fontloader/luaotfload-package.lua @@ -0,0 +1,96 @@ +-- +----------------------------------------------------------------------- +-- FILE: luaotfload-package.lua +-- DESCRIPTION: Luatex fontloader packaging +-- REQUIREMENTS: luatex +-- AUTHOR: Philipp Gesang +-- LICENSE: GNU GPL v2.0 +-- CREATED: 2015-03-29 12:07:33+0200 +----------------------------------------------------------------------- +-- + +--- The original initialization sequence by Hans Hagen, see the file +--- luatex-fonts.lua for details: +--- +--- [01] l-lua.lua +--- [02] l-lpeg.lua +--- [03] l-function.lua +--- [04] l-string.lua +--- [05] l-table.lua +--- [06] l-io.lua +--- [07] l-file.lua +--- [08] l-boolean.lua +--- [09] l-math.lua +--- [10] util-str.lua +--- [11] luatex-basics-gen.lua +--- [12] data-con.lua +--- [13] luatex-basics-nod.lua +--- [14] font-ini.lua +--- [15] font-con.lua +--- [16] luatex-fonts-enc.lua +--- [17] font-cid.lua +--- [18] font-map.lua +--- [19] luatex-fonts-syn.lua +--- [20] font-tfm.lua +--- [21] font-afm.lua +--- [22] font-afk.lua +--- [23] luatex-fonts-tfm.lua +--- [24] font-oti.lua +--- [25] font-otf.lua +--- [26] font-otb.lua +--- [27] luatex-fonts-inj.lua +--- [28] luatex-fonts-ota.lua +--- [29] luatex-fonts-otn.lua +--- [30] font-otp.lua +--- [31] luatex-fonts-lua.lua +--- [32] font-def.lua +--- [33] luatex-fonts-def.lua +--- [34] luatex-fonts-ext.lua +--- [35] luatex-fonts-cbk.lua +--- +--- Of these, nos. 01--10 are provided by the Lualibs. Keeping them +--- around in the Luaotfload fontloader is therefore unnecessary. +--- Packaging needs to account for this difference. + +loadmodule "l-lua.lua" +loadmodule "l-lpeg.lua" +loadmodule "l-function.lua" +loadmodule "l-string.lua" +loadmodule "l-table.lua" +loadmodule "l-io.lua" +loadmodule "l-file.lua" +loadmodule "l-boolean.lua" +loadmodule "l-math.lua" +loadmodule "util-str.lua" + +--- The files below constitute the “fontloader proper”. Some of the +--- functionality like file resolvers is overloaded later by +--- Luaotfload. Consequently, the resulting package is pretty +--- bare-bones and not usable independently. + +loadmodule("luatex-basics-gen.lua") +loadmodule("data-con.lua") +loadmodule("luatex-basics-nod.lua") +loadmodule("font-ini.lua") +loadmodule("font-con.lua") +loadmodule("luatex-fonts-enc.lua") +loadmodule("font-cid.lua") +loadmodule("font-map.lua") +loadmodule("luatex-fonts-syn.lua") +loadmodule("font-tfm.lua") +loadmodule("font-afm.lua") +loadmodule("font-afk.lua") +loadmodule("luatex-fonts-tfm.lua") +loadmodule("font-oti.lua") +loadmodule("font-otf.lua") +loadmodule("font-otb.lua") +loadmodule("luatex-fonts-inj.lua") +loadmodule("luatex-fonts-ota.lua") +loadmodule("luatex-fonts-otn.lua") +loadmodule("font-otp.lua") +loadmodule("luatex-fonts-lua.lua") +loadmodule("font-def.lua") +loadmodule("luatex-fonts-def.lua") +loadmodule("luatex-fonts-ext.lua") +loadmodule("luatex-fonts-cbk.lua") + diff --git a/src/fontloader/misc/fontloader-basics.tex b/src/fontloader/misc/fontloader-basics.tex index abe4989..1180c68 100644 --- a/src/fontloader/misc/fontloader-basics.tex +++ b/src/fontloader/misc/fontloader-basics.tex @@ -20,4 +20,74 @@ {\global\advance\lastallocatedattribute 1 \attributedef#1\lastallocatedattribute} +% maybe we will have luatex-basics.lua some day for instance when more +% (pdf) primitives have moved to macros) + +\directlua { + + gadgets = gadgets or { } % reserved namespace + + gadgets.functions = { } + local registered = {} + + function gadgets.functions.reverve() + local numb = newtoken.scan_int() + local name = newtoken.scan_string() + local okay = string.gsub(name,"[\string\\ ]","") + registered[okay] = numb + texio.write_nl("reserving lua function '"..okay.."' with number "..numb) + end + + function gadgets.functions.register(name,f) + local okay = string.gsub(name,"[\string\\ ]","") + local numb = registered[okay] + if numb then + texio.write_nl("registering lua function '"..okay.."' with number "..numb) + lua.get_functions_table()[numb] = f + else + texio.write_nl("lua function '"..okay.."' is not reserved") + end + end + +} + +\newcount\lastallocatedluafunction + +\def\newluafunction#1% + {\ifdefined#1\else + \global\advance\lastallocatedluafunction 1 + \global\chardef#1\lastallocatedluafunction + \directlua{gadgets.functions.reserve()}#1{\detokenize{#1}}% + \fi} + +% an example of usage (if we ever support it it will go to the plain gadgets module): +% +% \directlua { +% +% local cct = nil +% local chr = nil +% +% gadgets.functions.register("UcharcatLuaOne",function() +% chr = newtoken.scan_int() +% cct = tex.getcatcode(chr) +% tex.setcatcode(chr,newtoken.scan_int()) +% tex.sprint(unicode.utf8.char(chr)) +% end) +% +% gadgets.functions.register("UcharcatLuaTwo",function() +% tex.setcatcode(chr,cct) +% end) +% +% } +% +% \def\Ucharcat +% {\expandafter\expandafter\expandafter\luafunction +% \expandafter\expandafter\expandafter\UcharcatLuaTwo +% \luafunction\UcharcatLuaOne} +% +% A:\the\catcode65:\Ucharcat 65 11:A:\the\catcode65\par +% A:\the\catcode65:\Ucharcat 65 5:A:\the\catcode65\par +% A:\the\catcode65:\Ucharcat 65 11:A:\the\catcode65\par + + \endinput diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua index bb96912..72fbb5c 100644 --- a/src/fontloader/misc/fontloader-font-con.lua +++ b/src/fontloader/misc/fontloader-font-con.lua @@ -507,6 +507,7 @@ function constructors.scale(tfmdata,specification) local nonames = properties.noglyphnames local haskerns = properties.haskerns or properties.mode == "base" -- we can have afm in node mode local hasligatures = properties.hasligatures or properties.mode == "base" -- we can have afm in node mode + local realdimensions = properties.realdimensions -- if changed and not next(changed) then changed = false @@ -618,6 +619,27 @@ function constructors.scale(tfmdata,specification) local width = description.width local height = description.height local depth = description.depth + if realdimensions then + -- this is mostly for checking issues + if not height or height == 0 then + local bb = description.boundingbox + local ht = bb[4] + if ht ~= 0 then + height = ht + end + if not depth or depth == 0 then + local dp = -bb[2] + if dp ~= 0 then + depth = dp + end + end + elseif not depth or depth == 0 then + local dp = -description.boundingbox[2] + if dp ~= 0 then + depth = dp + end + end + end if width then width = hdelta*width else width = scaledwidth end if height then height = vdelta*height else height = scaledheight end -- if depth then depth = vdelta*depth else depth = scaleddepth end diff --git a/src/fontloader/misc/fontloader-font-map.lua b/src/fontloader/misc/fontloader-font-map.lua index e26f28e..69474ba 100644 --- a/src/fontloader/misc/fontloader-font-map.lua +++ b/src/fontloader/misc/fontloader-font-map.lua @@ -23,6 +23,8 @@ local fonts = fonts or { } local mappings = fonts.mappings or { } fonts.mappings = mappings +local allocate = utilities.storage.allocate + --[[ldx-- <p>Eventually this code will disappear because map files are kind of obsolete. Some code may move to runtime or auxiliary modules.</p> @@ -194,7 +196,7 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * -- to be completed .. for fonts that use unicodes for ligatures which -- is a actually a bad thing and should be avoided in the first place -local overloads = { +local overloads = allocate { IJ = { name = "I_J", unicode = { 0x49, 0x4A }, mess = 0x0132 }, ij = { name = "i_j", unicode = { 0x69, 0x6A }, mess = 0x0133 }, ff = { name = "f_f", unicode = { 0x66, 0x66 }, mess = 0xFB00 }, @@ -311,6 +313,59 @@ function mappings.addtounicode(data,filename) -- The next time I look into this, I'll add an extra analysis step to the otf loader (we can -- resolve some tounicodes by looking into the gsub data tables that are bound to glyphs. -- +-- a real tricky last resort: +-- +-- local lookups = glyph.lookups +-- if lookups then +-- for _, lookup in next, lookups do -- assume consistency else we need to sort +-- for i=1,#lookup do +-- local l = lookup[i] +-- if l.type == "ligature" then +-- local s = l.specification +-- if s.char == glyph.name then +-- local components = s.components +-- if components then +-- local t, n = { }, 0 +-- unicode = true +-- for l=1,#components do +-- local base = components[l] +-- local u = unicodes[base] or unicodevector[base] +-- if not u then +-- break +-- elseif type(u) == "table" then +-- if u[1] >= private then +-- unicode = false +-- break +-- end +-- n = n + 1 +-- t[n] = u[1] +-- else +-- if u >= private then +-- unicode = false +-- break +-- end +-- n = n + 1 +-- t[n] = u +-- end +-- end +-- if n == 0 then -- done then +-- -- nothing +-- elseif n == 1 then +-- glyph.unicode = t[1] +-- else +-- glyph.unicode = t +-- end +-- nl = nl + 1 +-- break +-- end +-- end +-- end +-- end +-- if unicode then +-- break +-- end +-- end +-- end if not unicode or unicode == "" then local split = lpegmatch(namesplitter,name) local nsplit = split and #split or 0 diff --git a/src/fontloader/misc/fontloader-font-otf.lua b/src/fontloader/misc/fontloader-font-otf.lua index c7e83a4..e7a97c6 100644 --- a/src/fontloader/misc/fontloader-font-otf.lua +++ b/src/fontloader/misc/fontloader-font-otf.lua @@ -36,6 +36,7 @@ local elapsedtime = statistics.elapsedtime local findbinfile = resolvers.findbinfile local trace_private = false registertracker("otf.private", function(v) trace_private = v end) +local trace_subfonts = false registertracker("otf.subfonts", function(v) trace_subfonts = 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) @@ -53,7 +54,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.803 -- beware: also sync font-mis.lua +otf.version = 2.812 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) local hashes = fonts.hashes @@ -107,6 +108,7 @@ registerdirective("fonts.otf.loader.pack", function(v) packdata = registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end) registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end) registerdirective("fonts.otf.loader.overloadkerns", function(v) overloadkerns = v end) +-----------------("fonts.otf.loader.alldimensions", function(v) alldimensions = v end) function otf.fileformat(filename) local leader = lower(io.loadchunk(filename,4)) @@ -637,17 +639,27 @@ actions["add dimensions"] = function(data,filename) -- d.name = ".notdef" -- end if bb then - local ht, dp = bb[4], -bb[2] - if ht == 0 or ht < 0 then - -- not set - else - d.height = ht - end - if dp == 0 or dp < 0 then - -- not set - else - d.depth = dp - end + local ht = bb[4] + local dp = -bb[2] + -- if alldimensions then + -- if ht ~= 0 then + -- d.height = ht + -- end + -- if dp ~= 0 then + -- d.depth = dp + -- end + -- else + if ht == 0 or ht < 0 then + -- not set + else + d.height = ht + end + if dp == 0 or dp < 0 then + -- not set + else + d.depth = dp + end + -- end end end end @@ -688,6 +700,7 @@ end -- not setting hasitalics and class (when nil) during table cronstruction can save some mem actions["prepare glyphs"] = function(data,filename,raw) + local tableversion = tonumber(raw.table_version) or 0 local rawglyphs = raw.glyphs local rawsubfonts = raw.subfonts local rawcidinfo = raw.cidinfo @@ -711,81 +724,139 @@ actions["prepare glyphs"] = function(data,filename,raw) 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 + local nofnames = 0 + local nofunicodes = 0 + local cidunicodes = cidmap.unicodes + local cidnames = cidmap.names + local cidtotal = 0 + local unique = trace_subfonts and { } for cidindex=1,#rawsubfonts do local subfont = rawsubfonts[cidindex] local cidglyphs = subfont.glyphs if includesubfonts then metadata.subfonts[cidindex] = somecopy(subfont) end - -- we have delayed loading so we cannot use next - for index=0,subfont.glyphcnt-1 do -- we could take the previous glyphcnt instead of 0 - local glyph = cidglyphs[index] - if glyph then - local unicode = glyph.unicode - if unicode >= 0x00E000 and unicode <= 0x00F8FF then - unicode = -1 - elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFD then - unicode = -1 - elseif unicode >= 0x100000 and unicode <= 0x10FFFD then - unicode = -1 - end - local name = glyph.name or cidnames[index] - if not unicode or unicode == -1 then -- or unicode >= criterium then - unicode = cidunicodes[index] - end - if unicode and descriptions[unicode] then - if trace_private then - report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) + local cidcnt, cidmin, cidmax + if tableversion > 0.3 then + -- we have delayed loading so we cannot use next + cidcnt = subfont.glyphcnt + cidmin = subfont.glyphmin + cidmax = subfont.glyphmax + else + cidcnt = subfont.glyphcnt + cidmin = 0 + cidmax = cidcnt - 1 + end + if trace_subfonts then + local cidtot = cidmax - cidmin + 1 + cidtotal = cidtotal + cidtot + report_otf("subfont: %i, min: %i, max: %i, cnt: %i, n: %i",cidindex,cidmin,cidmax,cidtot,cidcnt) + end + if cidcnt > 0 then + for cidslot=cidmin,cidmax do + local glyph = cidglyphs[cidslot] + if glyph then + local index = tableversion > 0.3 and glyph.orig_pos or cidslot + if trace_subfonts then + unique[index] = true end - unicode = -1 - end - if not unicode or unicode == -1 then -- or unicode >= criterium then - if not name then - name = format("u%06X.ctx",private) + local unicode = glyph.unicode + if unicode >= 0x00E000 and unicode <= 0x00F8FF then + unicode = -1 + elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFD then + unicode = -1 + elseif unicode >= 0x100000 and unicode <= 0x10FFFD then + unicode = -1 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) + local name = glyph.name or cidnames[index] + if not unicode or unicode == -1 then -- or unicode >= criterium then + unicode = cidunicodes[index] end - private = private + 1 - nofnames = nofnames + 1 - else - -- if unicode > criterium then - -- local taken = descriptions[unicode] - -- if taken then - -- private = private + 1 - -- descriptions[private] = taken - -- unicodes[taken.name] = private - -- indices[taken.index] = private - -- if trace_private then - -- report_otf("slot %U is moved to %U due to private in font",unicode) - -- end - -- end - -- end - if not name then - name = format("u%06X.ctx",unicode) + if unicode and descriptions[unicode] then + if trace_private then + report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) + end + unicode = -1 + end + if not unicode or unicode == -1 then -- or unicode >= criterium then + if not name then + name = format("u%06X.ctx",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 unicode > criterium then + -- local taken = descriptions[unicode] + -- if taken then + -- private = private + 1 + -- descriptions[private] = taken + -- unicodes[taken.name] = private + -- indices[taken.index] = private + -- if trace_private then + -- report_otf("slot %U is moved to %U due to private in font",unicode) + -- end + -- end + -- end + if not name then + name = format("u%06X.ctx",unicode) + end + unicodes[name] = unicode + nofunicodes = nofunicodes + 1 end - unicodes[name] = unicode - nofunicodes = nofunicodes + 1 + indices[index] = unicode -- each index is unique (at least now) + local description = { + -- width = glyph.width, + boundingbox = glyph.boundingbox, + -- name = glyph.name or name or "unknown", -- uniXXXX + name = name or "unknown", -- uniXXXX + cidindex = cidindex, + index = cidslot, + glyph = glyph, + } + descriptions[unicode] = description +local altuni = glyph.altuni +if altuni then + -- local d + for i=1,#altuni do + local a = altuni[i] + local u = a.unicode + if u ~= unicode then + local v = a.variant + if v then + -- tricky: no addition to d? needs checking but in practice such dups are either very simple + -- shapes or e.g cjk with not that many features + local vv = variants[v] + if vv then + vv[u] = unicode + else -- xits-math has some: + vv = { [u] = unicode } + variants[v] = vv + end + -- elseif d then + -- d[#d+1] = u + -- else + -- d = { u } + end + end + end + -- if d then + -- duplicates[unicode] = d -- is this needed ? + -- end +end end - indices[index] = unicode -- each index is unique (at least now) - local description = { - -- width = glyph.width, - boundingbox = glyph.boundingbox, - name = glyph.name or name or "unknown", -- uniXXXX - cidindex = cidindex, - index = index, - glyph = glyph, - } - descriptions[unicode] = description - else - -- report_otf("potential problem: glyph %U is used but empty",index) end + else + report_otf("potential problem: no glyphs found in subfont %i",cidindex) end end + if trace_subfonts then + report_otf("nofglyphs: %i, unique: %i",cidtotal,table.count(unique)) + end if trace_loading then report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames) end @@ -798,87 +869,97 @@ actions["prepare glyphs"] = function(data,filename,raw) else - for index=0,raw.glyphcnt-1 do -- not raw.glyphmax-1 (as that will crash) - local glyph = rawglyphs[index] - if glyph then - local unicode = glyph.unicode - local name = glyph.name - if not unicode or unicode == -1 then -- 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 - -- We have a font that uses and exposes the private area. As this is rather unreliable it's - -- advised no to trust slots here (better use glyphnames). Anyway, we need a double check: - -- we need to move already moved entries and we also need to bump the next private to after - -- the (currently) last slot. This could leave us with a hole but we have holes anyway. - if unicode > criterium then - -- \definedfont[file:HANBatang-LVT.ttf] \fontchar{uF0135} \char"F0135 - local taken = descriptions[unicode] - if taken then - if unicode >= private then - private = unicode + 1 -- restart private (so we can have mixed now) + local cnt = raw.glyphcnt or 0 + local min = tableversion > 0.3 and raw.glyphmin or 0 + local max = tableversion > 0.3 and raw.glyphmax or (raw.glyphcnt - 1) + if cnt > 0 then +-- for index=0,cnt-1 do + for index=min,max do + local glyph = rawglyphs[index] + if glyph then + local unicode = glyph.unicode + local name = glyph.name + if not unicode or unicode == -1 then -- 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 + -- We have a font that uses and exposes the private area. As this is rather unreliable it's + -- advised no to trust slots here (better use glyphnames). Anyway, we need a double check: + -- we need to move already moved entries and we also need to bump the next private to after + -- the (currently) last slot. This could leave us with a hole but we have holes anyway. + if unicode > criterium then + -- \definedfont[file:HANBatang-LVT.ttf] \fontchar{uF0135} \char"F0135 + local taken = descriptions[unicode] + if taken then + if unicode >= private then + private = unicode + 1 -- restart private (so we can have mixed now) + else + private = private + 1 -- move on + end + descriptions[private] = taken + unicodes[taken.name] = private + indices[taken.index] = private + if trace_private then + report_otf("slot %U is moved to %U due to private in font",unicode) + end else - private = private + 1 -- move on - end - descriptions[private] = taken - unicodes[taken.name] = private - indices[taken.index] = private - if trace_private then - report_otf("slot %U is moved to %U due to private in font",unicode) - end - else - if unicode >= private then - private = unicode + 1 -- restart (so we can have mixed now) + if unicode >= private then + private = unicode + 1 -- restart (so we can have mixed now) + end end end + unicodes[name] = unicode end - unicodes[name] = unicode - end - indices[index] = unicode - -- if not name then - -- name = format("u%06X",unicode) -- u%06X.ctx - -- end - descriptions[unicode] = { - -- width = glyph.width, - 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 - -- tricky: no addition to d? needs checking but in practice such dups are either very simple - -- shapes or e.g cjk with not that many features - local vv = variants[v] - if vv then - vv[u] = unicode - else -- xits-math has some: - vv = { [u] = unicode } - variants[v] = vv + indices[index] = unicode + -- if not name then + -- name = format("u%06X",unicode) -- u%06X.ctx + -- end + descriptions[unicode] = { + -- width = glyph.width, + 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 + if u ~= unicode then + local v = a.variant + if v then + -- tricky: no addition to d? needs checking but in practice such dups are either very simple + -- shapes or e.g cjk with not that many features + local vv = variants[v] + if vv then + vv[u] = unicode + else -- xits-math has some: + vv = { [u] = unicode } + variants[v] = vv + end + -- elseif d then + -- d[#d+1] = u + -- else + -- d = { u } + end end - -- elseif d then - -- d[#d+1] = u - -- else - -- d = { u } end + -- if d then + -- duplicates[unicode] = d -- is this needed ? + -- end end - -- if d then - -- duplicates[unicode] = d -- is this needed ? - -- end + else + report_otf("potential problem: glyph %U is used but empty",index) end - else - report_otf("potential problem: glyph %U is used but empty",index) end + else + report_otf("potential problem: no glyphs found") end end @@ -963,8 +1044,8 @@ actions["check encoding"] = function(data,filename,raw) end if mapdata then - mapdata.map = { } -- clear some memory - mapdata.backmap = { } -- clear some memory + mapdata.map = { } -- clear some memory (virtual and created each time anyway) + mapdata.backmap = { } -- clear some memory (virtual and created each time anyway) end end @@ -980,7 +1061,6 @@ actions["add duplicates"] = function(data,filename,raw) local unicodes = resources.unicodes -- name to unicode local indices = resources.indices -- index to unicodes local duplicates = resources.duplicates - for unicode, d in next, duplicates do local nofduplicates = #d if nofduplicates > 4 then diff --git a/src/fontloader/misc/fontloader-font-otp.lua b/src/fontloader/misc/fontloader-font-otp.lua index 63e4184..ebf36ed 100644 --- a/src/fontloader/misc/fontloader-font-otp.lua +++ b/src/fontloader/misc/fontloader-font-otp.lua @@ -9,6 +9,8 @@ if not modules then modules = { } end modules ['font-otp'] = { -- todo: pack math (but not that much to share) -- -- pitfall 5.2: hashed tables can suddenly become indexed with nil slots +-- +-- unless we sort all hashes we can get a different pack order (no big deal but size can differ) local next, type = next, type local sort, concat = table.sort, table.concat diff --git a/src/fontloader/misc/fontloader-fonts-cbk.lua b/src/fontloader/misc/fontloader-fonts-cbk.lua index ce19c88..81b5b6e 100644 --- a/src/fontloader/misc/fontloader-fonts-cbk.lua +++ b/src/fontloader/misc/fontloader-fonts-cbk.lua @@ -17,6 +17,9 @@ local nodes = nodes -- Fonts: (might move to node-gef.lua) local traverse_id = node.traverse_id +local free_node = node.free +local remove_node = node.remove + local glyph_code = nodes.nodecodes.glyph local disc_code = nodes.nodecodes.disc @@ -57,6 +60,8 @@ function nodes.handlers.nodepass(head) local basefonts = { } local prevfont = nil local basefont = nil + local variants = nil + local redundant = nil for n in traverse_id(glyph_code,head) do local font = n.font if font ~= prevfont then @@ -78,9 +83,46 @@ function nodes.handlers.nodepass(head) basefonts[#basefonts+1] = basefont end end + local resources = tfmdata.resources + variants = resources and resources.variants + variants = variants and next(variants) and variants or false + end + else + local tfmdata = fontdata[prevfont] + if tfmdata then + local resources = tfmdata.resources + variants = resources and resources.variants + variants = variants and next(variants) and variants or false end end end + if variants then + local char = n.char + if char >= 0xFE00 and (char <= 0xFE0F or (char >= 0xE0100 and char <= 0xE01EF)) then + local hash = variants[char] + if hash then + local p = n.prev + if p and p.id == glyph_code then + local variant = hash[p.char] + if variant then + p.char = variant + if not redundant then + redundant = { n } + else + redundant[#redundant+1] = n + end + end + end + end + end + end + end + if redundant then + for i=1,#redundant do + local n = redundant[i] + remove_node(head,n) + free_node(n) + end end for d in traverse_id(disc_code,head) do local r = d.replace diff --git a/src/fontloader/misc/fontloader-fonts-inj.lua b/src/fontloader/misc/fontloader-fonts-inj.lua index cb9ed89..332e920 100644 --- a/src/fontloader/misc/fontloader-fonts-inj.lua +++ b/src/fontloader/misc/fontloader-fonts-inj.lua @@ -647,10 +647,10 @@ local function inject_cursives(glyphs,nofglyphs) end end -local function inject_kerns(head,glyphs,nofglyphs) +local function inject_kerns(head,list,length) -- todo: pre/post/replace - for i=1,#glyphs do - local n = glyphs[i] + for i=1,length do + local n = list[i] local pn = rawget(properties,n) if pn then local i = rawget(pn,"injections") @@ -688,6 +688,9 @@ local function inject_everything(head,where) end inject_kerns(head,glyphs,nofglyphs) end + if nofmarks > 0 then + inject_kerns(head,marks,nofmarks) + end if keepregisteredcounts then keepregisteredcounts = false else @@ -998,7 +1001,7 @@ local function inject_pairs_only(head,where) if getsubtype(n) < 256 then local p = rawget(properties,n) if p then - local i = rawget(pn,"replaceinjections") + local i = rawget(p,"replaceinjections") if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then diff --git a/src/fontloader/misc/fontloader-fonts-otn.lua b/src/fontloader/misc/fontloader-fonts-otn.lua index 3f53078..dd3aa61 100644 --- a/src/fontloader/misc/fontloader-fonts-otn.lua +++ b/src/fontloader/misc/fontloader-fonts-otn.lua @@ -29,7 +29,6 @@ if not modules then modules = { } end modules ['font-otn'] = { -- todo: -- --- kerning is probably not yet ok for latin around dics nodes (interesting challenge) -- extension infrastructure (for usage out of context) -- sorting features according to vendors/renderers -- alternative loop quitters @@ -169,6 +168,7 @@ local report_chain = logs.reporter("fonts","otf chain") local report_process = logs.reporter("fonts","otf process") local report_prepare = logs.reporter("fonts","otf prepare") local report_warning = logs.reporter("fonts","otf warning") +local report_run = logs.reporter("fonts","otf run") registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) @@ -197,12 +197,18 @@ local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getchar = nuts.getchar +local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local delete_node = nuts.delete +local remove_node = nuts.remove local copy_node = nuts.copy +local copy_node_list = nuts.copy_list local find_node_tail = nuts.tail local flush_node_list = nuts.flush_list +local free_node = nuts.free local end_of_math = nuts.end_of_math +local traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id local setmetatableindex = table.setmetatableindex @@ -226,13 +232,15 @@ local dir_code = whatcodes.dir local localpar_code = whatcodes.localpar local discretionary_code = disccodes.discretionary +local regular_code = disccodes.regular +local automatic_code = disccodes.automatic local ligature_code = glyphcodes.ligature local privateattribute = attributes.private -- Something is messed up: we have two mark / ligature indices, one at the injection --- end and one here ... this is bases in KE's patches but there is something fishy +-- end and one here ... this is based on KE's patches but there is something fishy -- there as I'm pretty sure that for husayni we need some connection (as it's much -- more complex than an average font) but I need proper examples of all cases, not -- of only some. @@ -368,7 +376,7 @@ local function copy_glyph(g) -- next and prev are untouched ! end end --- +-- -- start is a mark and we need to keep that one @@ -1826,15 +1834,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end end - elseif f == 2 then - match = seq[1][32] else - for n=f-1,1 do - if not seq[n][32] then - match = false - break - end - end + match = false end end -- after @@ -1887,15 +1888,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end end - elseif s-l == 1 then - match = seq[s][32] else - for n=l+1,s do - if not seq[n][32] then - match = false - break - end - end + match = false end end end @@ -2627,6 +2621,7 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then if trace_steps then -- ? registerstep(head) end + end head = tonode(head) diff --git a/src/fontloader/misc/fontloader-l-lpeg.lua b/src/fontloader/misc/fontloader-l-lpeg.lua index 192e32f..55a0d89 100644 --- a/src/fontloader/misc/fontloader-l-lpeg.lua +++ b/src/fontloader/misc/fontloader-l-lpeg.lua @@ -10,6 +10,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { -- if i can use new features like capture / 2 and .B (at first sight the xml -- parser is some 5% slower) +-- lpeg.P("abc") is faster than lpeg.P("a") * lpeg.P("b") * lpeg.P("c") + -- a new lpeg fails on a #(1-P(":")) test and really needs a + P(-1) -- move utf -> l-unicode @@ -19,7 +21,7 @@ lpeg = require("lpeg") -- The latest lpeg doesn't have print any more, and even the new ones are not -- available by default (only when debug mode is enabled), which is a pitty as --- as it helps nailign down bottlenecks. Performance seems comparable: some 10% +-- as it helps nailing down bottlenecks. Performance seems comparable: some 10% -- slower pattern compilation, same parsing speed, although, -- -- local p = lpeg.C(lpeg.P(1)^0 * lpeg.P(-1)) @@ -834,121 +836,185 @@ end -- experiment: --- 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 - --- local function make(t) --- local p = P(false) --- local keys = sortedkeys(t) --- for i=1,#keys do --- local k = keys[i] --- local v = t[k] --- if next(v) then --- p = p + P(k) * make(v) --- else --- p = p + P(k) --- end --- end --- return p --- end - --- function lpeg.utfchartabletopattern(list) -- goes to util-lpg --- local tree = { } --- for i=1,#list do --- local t = tree --- for c in gmatch(list[i],".") do --- local tc = t[c] --- if not tc then --- tc = { } --- t[c] = tc --- end --- t = tc --- end --- end --- return make(tree) --- end +local p_false = P(false) +local p_true = P(true) -local function make(t,hash) - local p = P(false) +local function make(t) + local function making(t) + local p = p_false + local keys = sortedkeys(t) + for i=1,#keys do + local k = keys[i] + if k ~= "" then + local v = t[k] + if v == true then + p = p + P(k) * p_true + elseif v == false then + -- can't happen + else + p = p + P(k) * making(v) + end + end + end + if t[""] then + p = p + p_true + end + return p + end + local p = p_false local keys = sortedkeys(t) for i=1,#keys do local k = keys[i] - local v = t[k] - local h = hash[v] - if h then - if next(v) then - p = p + P(k) * (make(v,hash) + P(true)) + if k ~= "" then + local v = t[k] + if v == true then + p = p + P(k) * p_true + elseif v == false then + -- can't happen else - p = p + P(k) * P(true) + p = p + P(k) * making(v) end - else - if next(v) then - p = p + P(k) * make(v,hash) + end + end + return p +end + +local function collapse(t,x) + if type(t) ~= "table" then + return t, x + else + local n = next(t) + if n == nil then + return t, x + elseif next(t,n) == nil then + -- one entry + local k = n + local v = t[k] + if type(v) == "table" then + return collapse(v,x..k) else - p = p + P(k) + return v, x .. k + end + else + local tt = { } + for k, v in next, t do + local vv, kk = collapse(v,k) + tt[kk] = vv end + return tt, x end end - return p end function lpeg.utfchartabletopattern(list) -- goes to util-lpg local tree = { } - local hash = { } local n = #list if n == 0 then - -- we could always use this branch for s in next, list do local t = tree + local p, pk for c in gmatch(s,".") do - local tc = t[c] - if not tc then - tc = { } - t[c] = tc + if t == true then + t = { [c] = true, [""] = true } + p[pk] = t + p = t + t = false + elseif t == false then + t = { [c] = false } + p[pk] = t + p = t + t = false + else + local tc = t[c] + if not tc then + tc = false + t[c] = false + end + p = t + t = tc end - t = tc + pk = c + end + if t == false then + p[pk] = true + elseif t == true then + -- okay + else + t[""] = true end - hash[t] = s end else for i=1,n do - local t = tree local s = list[i] + local t = tree + local p, pk for c in gmatch(s,".") do - local tc = t[c] - if not tc then - tc = { } - t[c] = tc + if t == true then + t = { [c] = true, [""] = true } + p[pk] = t + p = t + t = false + elseif t == false then + t = { [c] = false } + p[pk] = t + p = t + t = false + else + local tc = t[c] + if not tc then + tc = false + t[c] = false + end + p = t + t = tc end - t = tc + pk = c + end + if t == false then + p[pk] = true + elseif t == true then + -- okay + else + t[""] = true end - hash[t] = s end end - return make(tree,hash) +-- collapse(tree,"") -- needs testing, maybe optional, slightly faster because P("x")*P("X") seems slower than P"(xX") (why) +-- inspect(tree) + return make(tree) end --- inspect ( lpeg.utfchartabletopattern { +-- local t = { "start", "stoep", "staart", "paard" } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) + +-- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) + +-- inspect(lpegmatch(p,"a")) +-- inspect(lpegmatch(p,"aa")) +-- inspect(lpegmatch(p,"aaaa")) +-- inspect(lpegmatch(p,"ac")) +-- inspect(lpegmatch(p,"bc")) +-- inspect(lpegmatch(p,"zzbczz")) +-- inspect(lpegmatch(p,"zzabezz")) +-- inspect(lpegmatch(p,"ab")) +-- inspect(lpegmatch(p,"abc")) +-- inspect(lpegmatch(p,"abe")) +-- inspect(lpegmatch(p,"xa")) +-- inspect(lpegmatch(p,"bx")) +-- inspect(lpegmatch(p,"bax")) +-- inspect(lpegmatch(p,"abxyz")) +-- inspect(lpegmatch(p,"foobarbefcrap")) + +-- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) +-- inspect(lpegmatch(p," ^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^ ^^^^^^^ ")) + +-- local t = { ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) +-- inspect(lpegmatch(p," ^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^ ^^^^^^^ ")) + +-- lpeg.utfchartabletopattern { -- utfchar(0x00A0), -- nbsp -- utfchar(0x2000), -- enquad -- utfchar(0x2001), -- emquad @@ -964,7 +1030,7 @@ end -- utfchar(0x200B), -- zerowidthspace -- utfchar(0x202F), -- narrownobreakspace -- utfchar(0x205F), -- math thinspace --- } ) +-- } -- a few handy ones: -- diff --git a/src/fontloader/misc/fontloader-l-math.lua b/src/fontloader/misc/fontloader-l-math.lua index 43f60b5..ec62919 100644 --- a/src/fontloader/misc/fontloader-l-math.lua +++ b/src/fontloader/misc/fontloader-l-math.lua @@ -8,6 +8,10 @@ if not modules then modules = { } end modules ['l-math'] = { local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan +if not math.ceiling then + math.ceiling = math.ceil +end + if not math.round then function math.round(x) return floor(x + 0.5) end end diff --git a/src/fontloader/misc/fontloader-l-table.lua b/src/fontloader/misc/fontloader-l-table.lua index 97e0441..b02f210 100644 --- a/src/fontloader/misc/fontloader-l-table.lua +++ b/src/fontloader/misc/fontloader-l-table.lua @@ -39,7 +39,7 @@ end function table.keys(t) if t then local keys, k = { }, 0 - for key, _ in next, t do + for key in next, t do k = k + 1 keys[k] = key end @@ -50,44 +50,126 @@ function table.keys(t) end -- local function compare(a,b) --- local ta, tb = type(a), type(b) -- needed, else 11 < 2 --- if ta == tb then +-- local ta = type(a) -- needed, else 11 < 2 +-- local tb = type(b) -- needed, else 11 < 2 +-- if ta == tb and ta == "number" then -- return a < b -- else -- return tostring(a) < tostring(b) -- not that efficient -- end -- end +-- local function compare(a,b) +-- local ta = type(a) -- needed, else 11 < 2 +-- local tb = type(b) -- needed, else 11 < 2 +-- if ta == tb and (ta == "number" or ta == "string") then +-- return a < b +-- else +-- return tostring(a) < tostring(b) -- not that efficient +-- end +-- end + +-- local function sortedkeys(tab) +-- if tab then +-- local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed +-- for key in next, tab do +-- s = s + 1 +-- srt[s] = key +-- if category == 3 then +-- -- no further check +-- 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 compare(a,b) +-- local ta = type(a) -- needed, else 11 < 2 +-- local tb = type(b) -- needed, else 11 < 2 +-- if ta == tb and (ta == "number" or ta == "string") then +-- return a < b +-- else +-- return tostring(a) < tostring(b) -- not that efficient +-- end +-- end + +-- local function compare(a,b) +-- local ta = type(a) -- needed, else 11 < 2 +-- if ta == "number" or ta == "string" then +-- local tb = type(b) -- needed, else 11 < 2 +-- if ta == tb then +-- return a < b +-- end +-- end +-- return tostring(a) < tostring(b) -- not that efficient +-- end + local function compare(a,b) local ta = type(a) -- needed, else 11 < 2 - local tb = type(b) -- needed, else 11 < 2 - if ta == tb and ta == "number" then - return a < b - else - return tostring(a) < tostring(b) -- not that efficient + if ta == "number" then + local tb = type(b) -- needed, else 11 < 2 + if ta == tb then + return a < b + elseif tb == "string" then + return tostring(a) < b + end + elseif ta == "string" then + local tb = type(b) -- needed, else 11 < 2 + if ta == tb then + return a < b + else + return a < tostring(b) + end end + return tostring(a) < tostring(b) -- not that efficient end local function sortedkeys(tab) if tab then local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed - for key,_ in next, tab do + for key in next, tab do s = s + 1 srt[s] = key if category == 3 then -- no further check + elseif category == 1 then + if type(key) ~= "string" then + category = 3 + end + elseif category == 2 then + if type(key) ~= "number" then + category = 3 + end else local tkey = type(key) if tkey == "string" then - category = (category == 2 and 3) or 1 + category = 1 elseif tkey == "number" then - category = (category == 1 and 3) or 2 + category = 2 else category = 3 end end end - if category == 0 or category == 3 then + if s < 2 then + -- nothing to sort + elseif category == 3 then sort(srt,compare) else sort(srt) @@ -101,13 +183,15 @@ end local function sortedhashonly(tab) if tab then local srt, s = { }, 0 - for key,_ in next, tab do + for key in next, tab do if type(key) == "string" then s = s + 1 srt[s] = key end end - sort(srt) + if s > 1 then + sort(srt) + end return srt else return { } @@ -117,13 +201,15 @@ end local function sortedindexonly(tab) if tab then local srt, s = { }, 0 - for key,_ in next, tab do + for key in next, tab do if type(key) == "number" then s = s + 1 srt[s] = key end end - sort(srt) + if s > 1 then + sort(srt) + end return srt else return { } @@ -133,13 +219,15 @@ end local function sortedhashkeys(tab,cmp) -- fast one if tab then local srt, s = { }, 0 - for key,_ in next, tab do + for key in next, tab do if key then s= s + 1 srt[s] = key end end - sort(srt,cmp) + if s > 1 then + sort(srt,cmp) + end return srt else return { } @@ -149,7 +237,7 @@ end function table.allkeys(t) local keys = { } for k, v in next, t do - for k, v in next, v do + for k in next, v do keys[k] = true end end @@ -172,19 +260,21 @@ local function sortedhash(t,cmp) else s = sortedkeys(t) -- the robust one end - local n = 0 local m = #s - local function kv() -- (s) - if n < m then - n = n + 1 - local k = s[n] - return k, t[k] + if m == 1 then + return next, t + elseif m > 0 then + local n = 0 + return function() + if n < m then + n = n + 1 + local k = s[n] + return k, t[k] + end end end - return kv -- , s - else - return nothing end + return nothing end table.sortedhash = sortedhash @@ -328,7 +418,7 @@ end local function copy(t, tables) -- taken from lua wiki, slightly adapted tables = tables or { } - local tcopy = {} + local tcopy = { } if not tables[t] then tables[t] = tcopy end @@ -388,7 +478,7 @@ function table.fromhash(t) return hsh end -local noquotes, hexify, handle, reduce, compact, inline, functions +local noquotes, hexify, handle, compact, inline, functions local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', @@ -396,33 +486,67 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv 'NaN', 'goto', } +-- 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%X",v) +-- else +-- tt[nt] = tostring(v) -- tostring not needed +-- end +-- elseif tv == "string" then +-- nt = nt + 1 +-- tt[nt] = format("%q",v) +-- elseif tv == "boolean" then +-- nt = nt + 1 +-- tt[nt] = v and "true" or "false" +-- else +-- return nil +-- end +-- end +-- return tt +-- end +-- end +-- return nil +-- end + local function simple_table(t) - if #t > 0 then + local nt = #t + if nt > 0 then local n = 0 for _,v in next, t do n = n + 1 + -- if type(v) == "table" then + -- return nil + -- end end - if n == #t then - local tt, nt = { }, 0 - for i=1,#t do + if n == nt then + local tt = { } + for i=1,nt do local v = t[i] local tv = type(v) if tv == "number" then - nt = nt + 1 if hexify then - tt[nt] = format("0x%X",v) + tt[i] = format("0x%X",v) else - tt[nt] = tostring(v) -- tostring not needed + tt[i] = tostring(v) -- tostring not needed end elseif tv == "string" then - nt = nt + 1 - tt[nt] = format("%q",v) + tt[i] = format("%q",v) elseif tv == "boolean" then - nt = nt + 1 - tt[nt] = v and "true" or "false" + tt[i] = v and "true" or "false" else - tt = nil - break + return nil end end return tt @@ -480,14 +604,6 @@ local function do_serialize(root,name,depth,level,indexed) end -- we could check for k (index) being number (cardinal) if root and next(root) ~= nil then - -- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone) - -- if compact then - -- -- NOT: for k=1,#root do (we need to quit at nil) - -- for k,v in ipairs(root) do -- can we use next? - -- if not first then first = k end - -- last = last + 1 - -- end - -- end local first, last = nil, 0 if compact then last = #root @@ -503,12 +619,10 @@ local function do_serialize(root,name,depth,level,indexed) end local sk = sortedkeys(root) for i=1,#sk do - local k = sk[i] - local v = root[k] - --~ if v == root then - -- circular - --~ else - local tv, tk = type(v), type(k) + local k = sk[i] + local v = root[k] + local tv = type(v) + local tk = type(k) if compact and first and tk == "number" and k >= first and k <= last then if tv == "number" then if hexify then @@ -517,11 +631,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s %s,",depth,v)) -- %.99g end elseif tv == "string" then - if reduce and tonumber(v) then - handle(format("%s %s,",depth,v)) - else - handle(format("%s %q,",depth,v)) - end + handle(format("%s %q,",depth,v)) elseif tv == "table" then if next(v) == nil then handle(format("%s {},",depth)) @@ -577,34 +687,18 @@ local function do_serialize(root,name,depth,level,indexed) end end elseif tv == "string" then - if reduce and tonumber(v) then - if tk == "number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk == "boolean" then - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v)) + if tk == "number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) else - handle(format("%s [%q]=%s,",depth,k,v)) + handle(format("%s [%s]=%q,",depth,k,v)) end + elseif tk == "boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - if tk == "number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk == "boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",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 + handle(format("%s [%q]=%q,",depth,k,v)) end elseif tv == "table" then if next(v) == nil then @@ -690,7 +784,6 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%q]=%q,",depth,k,tostring(v))) end end - --~ end end end if level > 0 then @@ -707,7 +800,6 @@ local function serialize(_handle,root,name,specification) -- handle wins 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 @@ -724,7 +816,6 @@ local function serialize(_handle,root,name,specification) -- handle wins noquotes = false hexify = false handle = _handle or print - reduce = false compact = true inline = true functions = true @@ -798,15 +889,6 @@ end table.tohandle = serialize --- sometimes tables are real use (zapfino extra pro is some 85M) in which --- case a stepwise serialization is nice; actually, we could consider: --- --- for line in table.serializer(root,name,reduce,noquotes) do --- ...(line) --- end --- --- so this is on the todo list - local maxtab = 2*1024 function table.tofile(filename,root,name,specification) diff --git a/src/fontloader/misc/fontloader-mplib.tex b/src/fontloader/misc/fontloader-mplib.tex index 8af9f2d..09dd179 100644 --- a/src/fontloader/misc/fontloader-mplib.tex +++ b/src/fontloader/misc/fontloader-mplib.tex @@ -61,6 +61,7 @@ %D Now load the needed \LUA\ code. \directlua{dofile(kpse.find_file('luatex-mplib.lua'))} +% \directlua{dofile(resolvers.findfile('luatex-mplib.lua'))} %D The following code takes care of encapsulating the literals: diff --git a/src/fontloader/misc/fontloader-plain.tex b/src/fontloader/misc/fontloader-plain.tex index 1ea8558..c9a9e36 100644 --- a/src/fontloader/misc/fontloader-plain.tex +++ b/src/fontloader/misc/fontloader-plain.tex @@ -20,6 +20,7 @@ \input {luatex-math}% \input {luatex-languages}% \input {luatex-mplib}% + % \input {luatex-gadgets}% } \edef\fmtversion{\fmtversion+luatex} diff --git a/src/fontloader/misc/fontloader-util-str.lua b/src/fontloader/misc/fontloader-util-str.lua index a677a82..c2139b1 100644 --- a/src/fontloader/misc/fontloader-util-str.lua +++ b/src/fontloader/misc/fontloader-util-str.lua @@ -44,7 +44,12 @@ end if not number then number = { } end -- temp hack for luatex-fonts -local stripper = patterns.stripzeros +local stripper = patterns.stripzeros +local newline = patterns.newline +local endofstring = patterns.endofstring +local whitespace = patterns.whitespace +local spacer = patterns.spacer +local spaceortab = patterns.spaceortab local function points(n) n = tonumber(n) @@ -62,12 +67,12 @@ number.basepoints = basepoints -- str = " \n \ntest \n test\ntest " -- print("["..string.gsub(string.collapsecrlf(str),"\n","+").."]") -local rubish = patterns.spaceortab^0 * patterns.newline -local anyrubish = patterns.spaceortab + patterns.newline +local rubish = spaceortab^0 * newline +local anyrubish = spaceortab + newline local anything = patterns.anything -local stripped = (patterns.spaceortab^1 / "") * patterns.newline +local stripped = (spaceortab^1 / "") * newline local leading = rubish^0 / "" -local trailing = (anyrubish^1 * patterns.endofstring) / "" +local trailing = (anyrubish^1 * endofstring) / "" local redundant = rubish^3 / "\n" local pattern = Cs(leading * (trailing + redundant + stripped + anything)^0) @@ -129,7 +134,7 @@ local pattern = return "" end end - + patterns.newline * Cp() / function(position) + + newline * Cp() / function(position) extra, start = 0, position end + patterns.anything @@ -162,11 +167,6 @@ end -- return str -- end -local newline = patterns.newline -local endofstring = patterns.endofstring -local whitespace = patterns.whitespace -local spacer = patterns.spacer - local space = spacer^0 local nospace = space/"" local endofline = nospace * newline @@ -1117,3 +1117,9 @@ local pattern = function string.optionalquoted(str) return lpegmatch(pattern,str) or str end + +local pattern = Cs((newline / (os.newline or "\r") + 1)^0) + +function string.replacenewlines(str) + return lpegmatch(pattern,str) +end diff --git a/src/fontloader/runtime/fontloader-fontloader.lua b/src/fontloader/runtime/fontloader-fontloader.lua index b662152..d8095a2 100644 --- a/src/fontloader/runtime/fontloader-fontloader.lua +++ b/src/fontloader/runtime/fontloader-fontloader.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 03/10/15 12:09:17 +-- merge date : 05/24/15 12:42:55 do -- begin closure to overcome local limits and interference @@ -660,62 +660,142 @@ function lpeg.append(list,pp,delayed,checked) end return p end -local function make(t,hash) - local p=P(false) +local p_false=P(false) +local p_true=P(true) +local function make(t) + local function making(t) + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then + else + p=p+P(k)*making(v) + end + end + end + if t[""] then + p=p+p_true + end + return p + end + local p=p_false local keys=sortedkeys(t) for i=1,#keys do local k=keys[i] - local v=t[k] - local h=hash[v] - if h then - if next(v) then - p=p+P(k)*(make(v,hash)+P(true)) + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then else - p=p+P(k)*P(true) + p=p+P(k)*making(v) end - else - if next(v) then - p=p+P(k)*make(v,hash) + end + end + return p +end +local function collapse(t,x) + if type(t)~="table" then + return t,x + else + local n=next(t) + if n==nil then + return t,x + elseif next(t,n)==nil then + local k=n + local v=t[k] + if type(v)=="table" then + return collapse(v,x..k) else - p=p+P(k) + return v,x..k end + else + local tt={} + for k,v in next,t do + local vv,kk=collapse(v,k) + tt[kk]=vv + end + return tt,x end end - return p end function lpeg.utfchartabletopattern(list) local tree={} - local hash={} local n=#list if n==0 then for s in next,list do local t=tree + local p,pk for c in gmatch(s,".") do - local tc=t[c] - if not tc then - tc={} - t[c]=tc + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - t=tc + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true end - hash[t]=s end else for i=1,n do - local t=tree local s=list[i] + local t=tree + local p,pk for c in gmatch(s,".") do - local tc=t[c] - if not tc then - tc={} - t[c]=tc + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - t=tc + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true end - hash[t]=s end end - return make(tree,hash) + return make(tree) end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) @@ -961,7 +1041,7 @@ end function table.keys(t) if t then local keys,k={},0 - for key,_ in next,t do + for key in next,t do k=k+1 keys[k]=key end @@ -972,32 +1052,51 @@ function table.keys(t) end local function compare(a,b) local ta=type(a) - local tb=type(b) - if ta==tb and ta=="number" then - return a<b - else - return tostring(a)<tostring(b) + if ta=="number" then + local tb=type(b) + if ta==tb then + return a<b + elseif tb=="string" then + return tostring(a)<b + end + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) + end end + return tostring(a)<tostring(b) end local function sortedkeys(tab) if tab then local srt,category,s={},0,0 - for key,_ in next,tab do + for key in next,tab do s=s+1 srt[s]=key if category==3 then + elseif category==1 then + if type(key)~="string" then + category=3 + end + elseif category==2 then + if type(key)~="number" then + category=3 + end else local tkey=type(key) if tkey=="string" then - category=(category==2 and 3) or 1 + category=1 elseif tkey=="number" then - category=(category==1 and 3) or 2 + category=2 else category=3 end end end - if category==0 or category==3 then + if s<2 then + elseif category==3 then sort(srt,compare) else sort(srt) @@ -1010,13 +1109,15 @@ end local function sortedhashonly(tab) if tab then local srt,s={},0 - for key,_ in next,tab do + for key in next,tab do if type(key)=="string" then s=s+1 srt[s]=key end end - sort(srt) + if s>1 then + sort(srt) + end return srt else return {} @@ -1025,13 +1126,15 @@ end local function sortedindexonly(tab) if tab then local srt,s={},0 - for key,_ in next,tab do + for key in next,tab do if type(key)=="number" then s=s+1 srt[s]=key end end - sort(srt) + if s>1 then + sort(srt) + end return srt else return {} @@ -1040,13 +1143,15 @@ end local function sortedhashkeys(tab,cmp) if tab then local srt,s={},0 - for key,_ in next,tab do + for key in next,tab do if key then s=s+1 srt[s]=key end end - sort(srt,cmp) + if s>1 then + sort(srt,cmp) + end return srt else return {} @@ -1055,7 +1160,7 @@ end function table.allkeys(t) local keys={} for k,v in next,t do - for k,v in next,v do + for k in next,v do keys[k]=true end end @@ -1074,19 +1179,21 @@ local function sortedhash(t,cmp) else s=sortedkeys(t) end - local n=0 local m=#s - local function kv() - if n<m then - n=n+1 - local k=s[n] - return k,t[k] + if m==1 then + return next,t + elseif m>0 then + local n=0 + return function() + if n<m then + n=n+1 + local k=s[n] + return k,t[k] + end end end - return kv - else - return nothing end + return nothing end table.sortedhash=sortedhash table.sortedpairs=sortedhash @@ -1228,39 +1335,36 @@ function table.fromhash(t) end return hsh end -local noquotes,hexify,handle,reduce,compact,inline,functions +local noquotes,hexify,handle,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', 'NaN','goto', } local function simple_table(t) - if #t>0 then + local nt=#t + if nt>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 + if n==nt then + local tt={} + for i=1,nt do local v=t[i] local tv=type(v) if tv=="number" then - nt=nt+1 if hexify then - tt[nt]=format("0x%X",v) + tt[i]=format("0x%X",v) else - tt[nt]=tostring(v) + tt[i]=tostring(v) end elseif tv=="string" then - nt=nt+1 - tt[nt]=format("%q",v) + tt[i]=format("%q",v) elseif tv=="boolean" then - nt=nt+1 - tt[nt]=v and "true" or "false" + tt[i]=v and "true" or "false" else - tt=nil - break + return nil end end return tt @@ -1314,7 +1418,8 @@ local function do_serialize(root,name,depth,level,indexed) for i=1,#sk do local k=sk[i] local v=root[k] - local tv,tk=type(v),type(k) + local tv=type(v) + local tk=type(k) if compact and first and tk=="number" and k>=first and k<=last then if tv=="number" then if hexify then @@ -1323,11 +1428,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s %s,",depth,v)) end elseif tv=="string" then - if reduce and tonumber(v) then - handle(format("%s %s,",depth,v)) - else - handle(format("%s %q,",depth,v)) - end + handle(format("%s %q,",depth,v)) elseif tv=="table" then if next(v)==nil then handle(format("%s {},",depth)) @@ -1383,34 +1484,18 @@ local function do_serialize(root,name,depth,level,indexed) end end elseif tv=="string" then - if reduce and tonumber(v) then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v)) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) else - handle(format("%s [%q]=%s,",depth,k,v)) + handle(format("%s [%s]=%q,",depth,k,v)) end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",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 + handle(format("%s [%q]=%q,",depth,k,v)) end elseif tv=="table" then if next(v)==nil then @@ -1507,7 +1592,6 @@ local function serialize(_handle,root,name,specification) 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 @@ -1524,7 +1608,6 @@ local function serialize(_handle,root,name,specification) noquotes=false hexify=false handle=_handle or print - reduce=false compact=true inline=true functions=true @@ -2658,6 +2741,9 @@ if not modules then modules={} end modules ['l-math']={ license="see context related readme files" } local floor,sin,cos,tan=math.floor,math.sin,math.cos,math.tan +if not math.ceiling then + math.ceiling=math.ceil +end if not math.round then function math.round(x) return floor(x+0.5) end end @@ -2715,6 +2801,11 @@ else end if not number then number={} end local stripper=patterns.stripzeros +local newline=patterns.newline +local endofstring=patterns.endofstring +local whitespace=patterns.whitespace +local spacer=patterns.spacer +local spaceortab=patterns.spaceortab local function points(n) n=tonumber(n) return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) @@ -2725,12 +2816,12 @@ local function basepoints(n) end number.points=points number.basepoints=basepoints -local rubish=patterns.spaceortab^0*patterns.newline -local anyrubish=patterns.spaceortab+patterns.newline +local rubish=spaceortab^0*newline +local anyrubish=spaceortab+newline local anything=patterns.anything -local stripped=(patterns.spaceortab^1/"")*patterns.newline +local stripped=(spaceortab^1/"")*newline local leading=rubish^0/"" -local trailing=(anyrubish^1*patterns.endofstring)/"" +local trailing=(anyrubish^1*endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) function strings.collapsecrlf(str) @@ -2776,17 +2867,13 @@ local pattern=Carg(1)/function(t) else return "" end - end+patterns.newline*Cp()/function(position) + end+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) end -local newline=patterns.newline -local endofstring=patterns.endofstring -local whitespace=patterns.whitespace -local spacer=patterns.spacer local space=spacer^0 local nospace=space/"" local endofline=nospace*newline @@ -3355,6 +3442,10 @@ local pattern=Cs(dquote*(equote-P(-2))^0*dquote) function string.optionalquoted(str) return lpegmatch(pattern,str) or str end +local pattern=Cs((newline/(os.newline or "\r")+1)^0) +function string.replacenewlines(str) + return lpegmatch(pattern,str) +end end -- closure @@ -4336,7 +4427,8 @@ function constructors.scale(tfmdata,specification) local stackmath=not properties.nostackmath local nonames=properties.noglyphnames local haskerns=properties.haskerns or properties.mode=="base" - local hasligatures=properties.hasligatures or properties.mode=="base" + local hasligatures=properties.hasligatures or properties.mode=="base" + local realdimensions=properties.realdimensions if changed and not next(changed) then changed=false end @@ -4417,6 +4509,26 @@ function constructors.scale(tfmdata,specification) local width=description.width local height=description.height local depth=description.depth + if realdimensions then + if not height or height==0 then + local bb=description.boundingbox + local ht=bb[4] + if ht~=0 then + height=ht + end + if not depth or depth==0 then + local dp=-bb[2] + if dp~=0 then + depth=dp + end + end + elseif not depth or depth==0 then + local dp=-description.boundingbox[2] + if dp~=0 then + depth=dp + end + end + end 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 @@ -5280,6 +5392,7 @@ local report_fonts=logs.reporter("fonts","loading") local fonts=fonts or {} local mappings=fonts.mappings or {} fonts.mappings=mappings +local allocate=utilities.storage.allocate local function loadlumtable(filename) local lumname=file.replacesuffix(file.basename(filename),"lum") local lumfile=resolvers.findfile(lumname,"map") or "" @@ -5381,7 +5494,7 @@ mappings.fromunicode16=fromunicode16 local ligseparator=P("_") local varseparator=P(".") local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0) -local overloads={ +local overloads=allocate { IJ={ name="I_J",unicode={ 0x49,0x4A },mess=0x0132 }, ij={ name="i_j",unicode={ 0x69,0x6A },mess=0x0133 }, ff={ name="f_f",unicode={ 0x66,0x66 },mess=0xFB00 }, @@ -7050,6 +7163,7 @@ 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_subfonts=false registertracker("otf.subfonts",function(v) trace_subfonts=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) @@ -7062,7 +7176,7 @@ local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.803 +otf.version=2.812 otf.cache=containers.define("fonts","otf",otf.version,true) local hashes=fonts.hashes local definers=fonts.definers @@ -7551,15 +7665,16 @@ actions["add dimensions"]=function(data,filename) 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 ht==0 or ht<0 then - else - d.height=ht - end - if dp==0 or dp<0 then - else - d.depth=dp - end + local ht=bb[4] + local dp=-bb[2] + if ht==0 or ht<0 then + else + d.height=ht + end + if dp==0 or dp<0 then + else + d.depth=dp + end end end end @@ -7594,6 +7709,7 @@ local function somecopy(old) end end actions["prepare glyphs"]=function(data,filename,raw) + local tableversion=tonumber(raw.table_version) or 0 local rawglyphs=raw.glyphs local rawsubfonts=raw.subfonts local rawcidinfo=raw.cidinfo @@ -7614,66 +7730,114 @@ actions["prepare glyphs"]=function(data,filename,raw) 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 + local nofnames=0 + local nofunicodes=0 + local cidunicodes=cidmap.unicodes + local cidnames=cidmap.names + local cidtotal=0 + local unique=trace_subfonts and {} 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 - if unicode>=0x00E000 and unicode<=0x00F8FF then - unicode=-1 - elseif unicode>=0x0F0000 and unicode<=0x0FFFFD then - unicode=-1 - elseif unicode>=0x100000 and unicode<=0x10FFFD then - unicode=-1 - end - local name=glyph.name or cidnames[index] - if not unicode or unicode==-1 then - unicode=cidunicodes[index] - end - if unicode and descriptions[unicode] then - if trace_private then - report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) + local cidcnt,cidmin,cidmax + if tableversion>0.3 then + cidcnt=subfont.glyphcnt + cidmin=subfont.glyphmin + cidmax=subfont.glyphmax + else + cidcnt=subfont.glyphcnt + cidmin=0 + cidmax=cidcnt-1 + end + if trace_subfonts then + local cidtot=cidmax-cidmin+1 + cidtotal=cidtotal+cidtot + report_otf("subfont: %i, min: %i, max: %i, cnt: %i, n: %i",cidindex,cidmin,cidmax,cidtot,cidcnt) + end + if cidcnt>0 then + for cidslot=cidmin,cidmax do + local glyph=cidglyphs[cidslot] + if glyph then + local index=tableversion>0.3 and glyph.orig_pos or cidslot + if trace_subfonts then + unique[index]=true end - unicode=-1 - end - if not unicode or unicode==-1 then - if not name then - name=format("u%06X.ctx",private) + local unicode=glyph.unicode + if unicode>=0x00E000 and unicode<=0x00F8FF then + unicode=-1 + elseif unicode>=0x0F0000 and unicode<=0x0FFFFD then + unicode=-1 + elseif unicode>=0x100000 and unicode<=0x10FFFD then + unicode=-1 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) + local name=glyph.name or cidnames[index] + if not unicode or unicode==-1 then + unicode=cidunicodes[index] end - private=private+1 - nofnames=nofnames+1 - else - if not name then - name=format("u%06X.ctx",unicode) + if unicode and descriptions[unicode] then + if trace_private then + report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) + end + unicode=-1 end - unicodes[name]=unicode - nofunicodes=nofunicodes+1 - end - indices[index]=unicode - local description={ - boundingbox=glyph.boundingbox, - name=glyph.name or name or "unknown", - cidindex=cidindex, - index=index, - glyph=glyph, - } - descriptions[unicode]=description - else + if not unicode or unicode==-1 then + if not name then + name=format("u%06X.ctx",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.ctx",unicode) + end + unicodes[name]=unicode + nofunicodes=nofunicodes+1 + end + indices[index]=unicode + local description={ + boundingbox=glyph.boundingbox, + name=name or "unknown", + cidindex=cidindex, + index=cidslot, + glyph=glyph, + } + descriptions[unicode]=description +local altuni=glyph.altuni +if altuni then + for i=1,#altuni do + local a=altuni[i] + local u=a.unicode + if u~=unicode then + local v=a.variant + if v then + local vv=variants[v] + if vv then + vv[u]=unicode + else + vv={ [u]=unicode } + variants[v]=vv + end + end + end + end +end + end end + else + report_otf("potential problem: no glyphs found in subfont %i",cidindex) end end + if trace_subfonts then + report_otf("nofglyphs: %i, unique: %i",cidtotal,table.count(unique)) + end if trace_loading then report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes,nofnames,nofunicodes+nofnames) end @@ -7684,68 +7848,77 @@ actions["prepare glyphs"]=function(data,filename,raw) 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 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 - if unicode>criterium then - local taken=descriptions[unicode] - if taken then - if unicode>=private then - private=unicode+1 + local cnt=raw.glyphcnt or 0 + local min=tableversion>0.3 and raw.glyphmin or 0 + local max=tableversion>0.3 and raw.glyphmax or (raw.glyphcnt-1) + if cnt>0 then + for index=min,max do + local glyph=rawglyphs[index] + if glyph then + local unicode=glyph.unicode + local name=glyph.name + if not unicode or unicode==-1 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 + if unicode>criterium then + local taken=descriptions[unicode] + if taken then + if unicode>=private then + private=unicode+1 + else + private=private+1 + end + descriptions[private]=taken + unicodes[taken.name]=private + indices[taken.index]=private + if trace_private then + report_otf("slot %U is moved to %U due to private in font",unicode) + end else - private=private+1 - end - descriptions[private]=taken - unicodes[taken.name]=private - indices[taken.index]=private - if trace_private then - report_otf("slot %U is moved to %U due to private in font",unicode) - end - else - if unicode>=private then - private=unicode+1 + if unicode>=private then + private=unicode+1 + end end end + unicodes[name]=unicode end - unicodes[name]=unicode - end - indices[index]=unicode - descriptions[unicode]={ - boundingbox=glyph.boundingbox, - name=name, - index=index, - glyph=glyph, - } - local altuni=glyph.altuni - if altuni then - 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 - else - vv={ [u]=unicode } - variants[v]=vv + indices[index]=unicode + descriptions[unicode]={ + boundingbox=glyph.boundingbox, + name=name, + index=index, + glyph=glyph, + } + local altuni=glyph.altuni + if altuni then + for i=1,#altuni do + local a=altuni[i] + local u=a.unicode + if u~=unicode then + local v=a.variant + if v then + local vv=variants[v] + if vv then + vv[u]=unicode + else + vv={ [u]=unicode } + variants[v]=vv + end + end end end end + else + report_otf("potential problem: glyph %U is used but empty",index) end - else - report_otf("potential problem: glyph %U is used but empty",index) end + else + report_otf("potential problem: no glyphs found") end end resources.private=private @@ -10398,9 +10571,9 @@ local function inject_cursives(glyphs,nofglyphs) end end end -local function inject_kerns(head,glyphs,nofglyphs) - for i=1,#glyphs do - local n=glyphs[i] +local function inject_kerns(head,list,length) + for i=1,length do + local n=list[i] local pn=rawget(properties,n) if pn then local i=rawget(pn,"injections") @@ -10437,6 +10610,9 @@ local function inject_everything(head,where) end inject_kerns(head,glyphs,nofglyphs) end + if nofmarks>0 then + inject_kerns(head,marks,nofmarks) + end if keepregisteredcounts then keepregisteredcounts=false else @@ -10727,7 +10903,7 @@ local function inject_pairs_only(head,where) if getsubtype(n)<256 then local p=rawget(properties,n) if p then - local i=rawget(pn,"replaceinjections") + local i=rawget(p,"replaceinjections") if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then @@ -11198,6 +11374,7 @@ local report_chain=logs.reporter("fonts","otf chain") local report_process=logs.reporter("fonts","otf process") local report_prepare=logs.reporter("fonts","otf prepare") local report_warning=logs.reporter("fonts","otf warning") +local report_run=logs.reporter("fonts","otf run") registertracker("otf.verbose_chain",function(v) otf.setcontextchain(v and "verbose") end) registertracker("otf.normal_chain",function(v) otf.setcontextchain(v and "normal") end) registertracker("otf.replacements","otf.singles,otf.multiples,otf.alternatives,otf.ligatures") @@ -11220,12 +11397,18 @@ local setprop=nuts.setprop local getfont=nuts.getfont local getsubtype=nuts.getsubtype local getchar=nuts.getchar +local insert_node_before=nuts.insert_before local insert_node_after=nuts.insert_after local delete_node=nuts.delete +local remove_node=nuts.remove local copy_node=nuts.copy +local copy_node_list=nuts.copy_list local find_node_tail=nuts.tail local flush_node_list=nuts.flush_list +local free_node=nuts.free local end_of_math=nuts.end_of_math +local traverse_nodes=nuts.traverse +local traverse_id=nuts.traverse_id local setmetatableindex=table.setmetatableindex local zwnj=0x200C local zwj=0x200D @@ -11243,6 +11426,8 @@ local math_code=nodecodes.math local dir_code=whatcodes.dir local localpar_code=whatcodes.localpar local discretionary_code=disccodes.discretionary +local regular_code=disccodes.regular +local automatic_code=disccodes.automatic local ligature_code=glyphcodes.ligature local privateattribute=attributes.private local a_state=privateattribute('state') @@ -12596,15 +12781,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end end - elseif f==2 then - match=seq[1][32] else - for n=f-1,1 do - if not seq[n][32] then - match=false - break - end - end + match=false end end if match and s>l then @@ -12654,15 +12832,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end end - elseif s-l==1 then - match=seq[s][32] else - for n=l+1,s do - if not seq[n][32] then - match=false - break - end - end + match=false end end end @@ -15039,6 +15210,8 @@ end local fonts=fonts local nodes=nodes local traverse_id=node.traverse_id +local free_node=node.free +local remove_node=node.remove local glyph_code=nodes.nodecodes.glyph local disc_code=nodes.nodecodes.disc local ligaturing=node.ligaturing @@ -15068,6 +15241,8 @@ function nodes.handlers.nodepass(head) local basefonts={} local prevfont=nil local basefont=nil + local variants=nil + local redundant=nil for n in traverse_id(glyph_code,head) do local font=n.font if font~=prevfont then @@ -15089,10 +15264,47 @@ function nodes.handlers.nodepass(head) basefonts[#basefonts+1]=basefont end end + local resources=tfmdata.resources + variants=resources and resources.variants + variants=variants and next(variants) and variants or false + end + else + local tfmdata=fontdata[prevfont] + if tfmdata then + local resources=tfmdata.resources + variants=resources and resources.variants + variants=variants and next(variants) and variants or false + end + end + end + if variants then + local char=n.char + if char>=0xFE00 and (char<=0xFE0F or (char>=0xE0100 and char<=0xE01EF)) then + local hash=variants[char] + if hash then + local p=n.prev + if p and p.id==glyph_code then + local variant=hash[p.char] + if variant then + p.char=variant + if not redundant then + redundant={ n } + else + redundant[#redundant+1]=n + end + end + end end end end end + if redundant then + for i=1,#redundant do + local n=redundant[i] + remove_node(head,n) + free_node(n) + end + end for d in traverse_id(disc_code,head) do local r=d.replace if r then |