From f8d460cfb7c7cf2ff8ac5d0e1b6d9436c50dae7d Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 18 Dec 2015 00:13:22 +0100 Subject: [features] update addfeatures() from upstream font-otc.lua --- src/luaotfload-features.lua | 379 +++++++++++++++++++++++++++++--------------- 1 file changed, 253 insertions(+), 126 deletions(-) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 962806c..bcf9968 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -946,146 +946,273 @@ local types = { setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" +--- start locals for addfeature() + +local otf = handlers and handlers.otf --- filled in later during initialization + +local normalized = { + substitution = "substitution", + single = "substitution", + ligature = "ligature", + alternate = "alternate", + multiple = "multiple", + kern = "kern", +} + +local types = { + substitution = "gsub_single", + ligature = "gsub_ligature", + alternate = "gsub_alternate", + multiple = "gsub_multiple", + kern = "gpos_pair", +} + +--- stop locals for addfeature() + local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } -local noflags = { } +local noflags = { } -local function addfeature (data, feature, specifications) +local function addfeature(data,feature,specifications) local descriptions = data.descriptions local resources = data.resources - local lookups = resources.lookups - local gsubfeatures = resources.features.gsub + local features = resources.features + local sequences = resources.sequences + if not features or not sequences then + return + end + local gsubfeatures = features.gsub if gsubfeatures and gsubfeatures[feature] then - -- already present - else - local sequences = resources.sequences - local fontfeatures = resources.features - local unicodes = resources.unicodes - local lookuptypes = resources.lookuptypes - local splitter = lpeg.splitter(" ",unicodes) - local done = 0 - local skip = 0 - if not specifications[1] then - -- so we accept a one entry specification - specifications = { specifications } + return -- already present + end + local fontfeatures = resources.features or everywhere + local unicodes = resources.unicodes + local splitter = lpeg.splitter(" ",unicodes) + local done = 0 + local skip = 0 + if not specifications[1] then + -- so we accept a one entry specification + specifications = { specifications } + end + + local function tounicode(code) + if not code then + return + elseif type(code) == "number" then + return code + else + return unicodes[code] or utfbyte(code) end - -- subtables are tables themselves but we also accept flattened singular subtables - for s=1,#specifications do - local specification = specifications[s] - local valid = specification.valid - if not valid or valid(data,specification,feature) then - local initialize = specification.initialize - if initialize then - -- when false is returned we initialize only once - specification.initialize = initialize(specification) and initialize or nil - end - local askedfeatures = specification.features or everywhere - local subtables = specification.subtables or { specification.data } or { } - local featuretype = types[specification.type or "substitution"] - local featureflags = specification.flags or noflags - local featureorder = specification.order or { feature } - local added = false - local featurename = stringformat("ctx_%s_%s",feature,s) - local st = { } - for t=1,#subtables do - local list = subtables[t] - local full = stringformat("%s_%s",featurename,t) - st[t] = full - if featuretype == "gsub_ligature" then - lookuptypes[full] = "ligature" - for code, ligature in next, list do - local unicode = tonumber(code) or unicodes[code] - local description = descriptions[unicode] - if description then - local slookups = description.slookups - if type(ligature) == "string" then - ligature = { lpegmatch(splitter,ligature) } - end - local present = true - for i=1,#ligature do - if not descriptions[ligature[i]] then - present = false - break - end - end - if present then - if slookups then - slookups[full] = ligature - else - description.slookups = { [full] = ligature } - end - done, added = done + 1, true + end + + local coverup = otf.coverup + local coveractions = coverup.actions + local stepkey = coverup.stepkey + local register = coverup.register + + for s=1,#specifications do + local specification = specifications[s] + local valid = specification.valid + if not valid or valid(data,specification,feature) then + local initialize = specification.initialize + if initialize then + -- when false is returned we initialize only once + specification.initialize = initialize(specification,data) and initialize or nil + end + local askedfeatures = specification.features or everywhere + local askedsteps = specifications.steps or specification.subtables or { specification.data } or { } + local featuretype = normalized[specification.type or "substitution"] or "substitution" + local featureflags = specification.flags or noflags + local featureorder = specification.order or { feature } + local added = false + local nofsteps = 0 + local steps = { } + for i=1,#askedsteps do + local list = askedsteps[i] + local coverage = { } + local cover = coveractions[featuretype] + local format = nil + if not cover then + -- unknown + elseif featuretype == "substitution" then + for code, replacement in next, list do + local unicode = tounicode(code) + local description = descriptions[unicode] + if description then + if type(replacement) == "table" then + replacement = replacement[1] + end + replacement = tounicode(replacement) + if replacement and descriptions[replacement] then + cover(coverage,unicode,replacement) + done = done + 1 + else + skip = skip + 1 + end + else + skip = skip + 1 + end + end + elseif featuretype == "ligature" then + for code, ligature in next, list do + local unicode = tounicode(code) + local description = descriptions[unicode] + if description then + if type(ligature) == "string" then + ligature = { lpegmatch(splitter,ligature) } + end + local present = true + for i=1,#ligature do + local l = ligature[i] + local u = tounicode(l) + if descriptions[u] then + ligature[i] = u else - skip = skip + 1 + present = false + break end end + if present then + cover(coverage,unicode,ligature) + done = done + 1 + else + skip = skip + 1 + end + else + skip = skip + 1 end - elseif featuretype == "gsub_single" then - lookuptypes[full] = "substitution" - for code, replacement in next, list do - local unicode = tonumber(code) or unicodes[code] - local description = descriptions[unicode] - if description then - local slookups = description.slookups - replacement = tonumber(replacement) or unicodes[replacement] - if descriptions[replacement] then - if slookups then - slookups[full] = replacement - else - description.slookups = { [full] = replacement } - end - done, added = done + 1, true - end + end + elseif featuretype == "alternate" then + for code, replacement in next, list do + local unicode = tounicode(code) + local description = descriptions[unicode] + if not description then + skip = skip + 1 + elseif type(replacement) == "table" then + local r = { } + for i=1,#replacement do + local u = tounicode(replacement[i]) + r[i] = descriptions[u] and u or unicode + end + cover(coverage,unicode,r) + done = done + 1 + else + local u = tounicode(replacement) + if u then + cover(coverage,unicode,{ u }) + done = done + 1 + else + skip = skip + 1 end end end - end - if added then - -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } - for k, v in next, askedfeatures do - if v[1] then - askedfeatures[k] = tabletohash(v) + elseif featuretype == "multiple" then -- todo: unicode can be table + for code, replacement in next, list do + local unicode = tounicode(code) + local description = descriptions[unicode] + if not description then + skip = skip + 1 + elseif type(replacement) == "table" then + local r, n = { }, 0 + for i=1,#replacement do + local u = tounicode(replacement[i]) + if descriptions[u] then + n = n + 1 + r[n] = u + end + end + if n > 0 then + cover(coverage,unicode,r) + done = done + 1 + else + skip = skip + 1 + end + else + local u = tounicode(replacement) + if u then + cover(coverage,unicode,{ u }) + done = done + 1 + else + skip = skip + 1 + end end end - local sequence = { - chain = 0, - features = { [feature] = askedfeatures }, - flags = featureflags, - name = featurename, - order = featureorder, - subtables = st, - type = featuretype, - } - if specification.prepend then - insert(sequences,1,sequence) - else - insert(sequences,sequence) + elseif featuretype == "kern" then + for code, replacement in next, list do + local unicode = tounicode(code) + local description = descriptions[unicode] + if description and type(replacement) == "table" then + local r = { } + for k, v in next, replacement do + local u = tounicode(k) + if u then + r[u] = v + end + end + if next(r) then + cover(coverage,unicode,r) + done = done + 1 + else + skip = skip + 1 + end + else + skip = skip + 1 + end end - -- register in metadata (merge as there can be a few) - if not gsubfeatures then - gsubfeatures = { } - fontfeatures.gsub = gsubfeatures + format = "kern" + end + if next(coverage) then + added = true + nofsteps = nofsteps + 1 + steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) + end + end + if added then + -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } + for k, v in next, askedfeatures do + if v[1] then + askedfeatures[k] = table.tohash(v) end - local k = gsubfeatures[feature] - if not k then - k = { } - gsubfeatures[feature] = k + end + local sequence = { + chain = 0, + features = { [feature] = askedfeatures }, + flags = featureflags, + name = feature, -- not needed + order = featureorder, + [stepkey] = steps, + nofsteps = nofsteps, + type = types[featuretype], + } + if specification.prepend then + insert(sequences,1,sequence) + else + insert(sequences,sequence) + end + -- register in metadata (merge as there can be a few) + if not gsubfeatures then + gsubfeatures = { } + fontfeatures.gsub = gsubfeatures + end + local k = gsubfeatures[feature] + if not k then + k = { } + gsubfeatures[feature] = k + end + for script, languages in next, askedfeatures do + local kk = k[script] + if not kk then + kk = { } + k[script] = kk end - for script, languages in next, askedfeatures do - local kk = k[script] - if not kk then - kk = { } - k[script] = kk - end - for language, value in next, languages do - kk[language] = value - end + for language, value in next, languages do + kk[language] = value end end end end - if trace_loading then - report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) - end + end + if trace_loading then + report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) end end @@ -1097,10 +1224,10 @@ local tlig_specification = { features = everywhere, data = { [0x0022] = 0x201D, -- quotedblright - [0x0027] = 0x2019, -- quoteleft - [0x0060] = 0x2018, -- quoteright + --[0x0027] = 0x2019, -- quoteleft + --[0x0060] = 0x2018, -- quoteright }, - flags = { }, + flags = no_flags, order = { "tlig" }, prepend = true, }, @@ -1120,7 +1247,7 @@ local tlig_specification = { [0x00AB] = {0x003C, 0x003C}, -- LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK }, - flags = { }, + flags = no_flags, order = { "tlig" }, prepend = true, }, @@ -1133,7 +1260,7 @@ local tlig_specification = { [0x00A1] = {0x0021, 0x0060}, -- exclamdown [0x00BF] = {0x003F, 0x0060}, -- questiondown }, - flags = { }, + flags = no_flags, order = { "tlig" }, prepend = true, }, @@ -1183,7 +1310,7 @@ local anum_specification = { type = "substitution", features = { arab = { far = true, urd = true, snd = true } }, data = anum_persian, - flags = { }, + flags = no_flags, order = { "anum" }, valid = valid, }, @@ -1191,7 +1318,7 @@ local anum_specification = { type = "substitution", features = { arab = { ["*"] = true } }, data = anum_arabic, - flags = { }, + flags = no_flags, order = { "anum" }, valid = valid, }, @@ -1207,7 +1334,7 @@ return { return false end - local otf = fonts.handlers.otf + otf = fonts.handlers.otf local extrafeatures = { tlig = tlig_specification, -- cgit v1.2.3 From a2c098ec73840c855346b1afa8522585625b97d0 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 18 Dec 2015 00:44:32 +0100 Subject: [features] output feature definition info at higher noise level --- src/luaotfload-features.lua | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index bcf9968..5188051 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -948,6 +948,8 @@ setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" --- start locals for addfeature() +local utfbyte = unicode.utf8.byte + local otf = handlers and handlers.otf --- filled in later during initialization local normalized = { @@ -1224,10 +1226,10 @@ local tlig_specification = { features = everywhere, data = { [0x0022] = 0x201D, -- quotedblright - --[0x0027] = 0x2019, -- quoteleft - --[0x0060] = 0x2018, -- quoteright + [0x0027] = 0x2019, -- quoteleft + [0x0060] = 0x2018, -- quoteright }, - flags = no_flags, + flags = noflags, order = { "tlig" }, prepend = true, }, @@ -1247,7 +1249,7 @@ local tlig_specification = { [0x00AB] = {0x003C, 0x003C}, -- LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK }, - flags = no_flags, + flags = noflags, order = { "tlig" }, prepend = true, }, @@ -1260,7 +1262,7 @@ local tlig_specification = { [0x00A1] = {0x0021, 0x0060}, -- exclamdown [0x00BF] = {0x003F, 0x0060}, -- questiondown }, - flags = no_flags, + flags = noflags, order = { "tlig" }, prepend = true, }, @@ -1310,7 +1312,7 @@ local anum_specification = { type = "substitution", features = { arab = { far = true, urd = true, snd = true } }, data = anum_persian, - flags = no_flags, + flags = noflags, order = { "anum" }, valid = valid, }, @@ -1318,7 +1320,7 @@ local anum_specification = { type = "substitution", features = { arab = { ["*"] = true } }, data = anum_arabic, - flags = no_flags, + flags = noflags, order = { "anum" }, valid = valid, }, @@ -1328,7 +1330,7 @@ return { init = function () if not fonts and fonts.handlers then - logreport ("log", 0, "color", + logreport ("log", 0, "features", "OTF mechanisms missing -- did you forget to \z load a font loader?") return false @@ -1343,15 +1345,21 @@ return { } otf.enhancers.register ("check extra features", - function (data,filename, raw) + function (data, filename, raw) for feature, specification in next, extrafeatures do + logreport ("both", 3, "features", + "register synthetic feature ā€œ%sā€ for %s font ā€œ%sā€(%d)", + feature, + data.format, + tostring (data.metadata and data.metadata.fontname or ""), + data.subfont or -1) addfeature (data, feature, specification) end end) logreport = luaotfload.log.report if not fonts then - logreport ("log", 0, "color", + logreport ("log", 0, "features", "OTF mechanisms missing -- did you forget to \z load a font loader?") return false -- cgit v1.2.3 From bc4588e5d5c4392cb1491c57d8c0f12e2221e215 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 18 Dec 2015 08:07:08 +0100 Subject: [features] clean up font feature handling --- src/luaotfload-features.lua | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 5188051..749ffec 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -938,14 +938,6 @@ local report_otf = logs.reporter("fonts","otf loading") --HH]]-- -local types = { - substitution = "gsub_single", - ligature = "gsub_ligature", - alternate = "gsub_alternate", -} - -setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" - --- start locals for addfeature() local utfbyte = unicode.utf8.byte @@ -969,6 +961,8 @@ local types = { kern = "gpos_pair", } +setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" + --- stop locals for addfeature() local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } @@ -1220,6 +1214,8 @@ end ---[[ end snippet from font-otc.lua ]] +local tlig_order = { "tlig" } + local tlig_specification = { { type = "substitution", @@ -1230,7 +1226,7 @@ local tlig_specification = { [0x0060] = 0x2018, -- quoteright }, flags = noflags, - order = { "tlig" }, + order = tlig_order, prepend = true, }, { @@ -1250,7 +1246,7 @@ local tlig_specification = { [0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK }, flags = noflags, - order = { "tlig" }, + order = tlig_order, prepend = true, }, { @@ -1263,7 +1259,7 @@ local tlig_specification = { [0x00BF] = {0x003F, 0x0060}, -- questiondown }, flags = noflags, - order = { "tlig" }, + order = tlig_order, prepend = true, }, } -- cgit v1.2.3 From 92b6110cfde6deb63e328d47965bfa6ea26d35a1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 18 Dec 2015 08:29:09 +0100 Subject: [letterspace] fix access of invalid node field This addresses one error reported by u/priyadarshan: https://github.com/lualatex/luaotfload/issues/310 Some chained node field access got garbled during the update to nuts. --- src/luaotfload-letterspace.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index 5fa25f9..aa9157a 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -441,9 +441,9 @@ kerncharacters = function (head) setfield(after, "next", nil) replace = kerncharacters (before) replace = getnext(replace) - setfield(replace, "prev", nil) - setfield(after, "prev.next", nil) - setfield(disc, "replace", replace) + setfield(replace, "prev", nil) + setfield(getprev(after), "next", nil) + setfield(disc, "replace", replace) free_node(after) free_node(before) -- cgit v1.2.3 From e7347ebd913a5f080946f3d4d9e9ccbf060cacc5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 21 Dec 2015 06:19:24 +0100 Subject: [features] pull in upstream fixes Fixes the crash but apparently not the feature. --- src/luaotfload-features.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 749ffec..322a020 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -968,6 +968,8 @@ setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } local noflags = { } +local tohash = table.tohash + local function addfeature(data,feature,specifications) local descriptions = data.descriptions local resources = data.resources @@ -1016,17 +1018,18 @@ local function addfeature(data,feature,specifications) end local askedfeatures = specification.features or everywhere local askedsteps = specifications.steps or specification.subtables or { specification.data } or { } - local featuretype = normalized[specification.type or "substitution"] or "substitution" + local defaulttype = specification.type or "substitution" local featureflags = specification.flags or noflags local featureorder = specification.order or { feature } local added = false local nofsteps = 0 local steps = { } for i=1,#askedsteps do - local list = askedsteps[i] - local coverage = { } - local cover = coveractions[featuretype] - local format = nil + local list = askedsteps[i] + local coverage = { } + local cover = coveractions[featuretype] + local format = nil + local featuretype = normalized[list.type or defaulttype] or "substitution" if not cover then -- unknown elseif featuretype == "substitution" then @@ -1166,7 +1169,7 @@ local function addfeature(data,feature,specifications) -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } for k, v in next, askedfeatures do if v[1] then - askedfeatures[k] = table.tohash(v) + askedfeatures[k] = tohash(v) end end local sequence = { @@ -1212,6 +1215,7 @@ local function addfeature(data,feature,specifications) end end + ---[[ end snippet from font-otc.lua ]] local tlig_order = { "tlig" } -- cgit v1.2.3 From 9fa98cb5339972074a5c26e92f89b250f2de76c1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 21 Dec 2015 07:17:42 +0100 Subject: [letterspace] employ dedicated accessors where appropriate --- src/luaotfload-letterspace.lua | 85 +++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index aa9157a..f7c895f 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -20,17 +20,35 @@ local tonumber = tonumber local next = next local nodes, node, fonts = nodes, node, fonts +local nodedirect = nodes.nuts + +local getfield = nodedirect.getfield +local setfield = nodedirect.setfield + +local field_setter = function (name) return function (n, ...) setfield (n, name, ...) end end +local field_getter = function (name) return function (n, ...) getfield (n, name, ...) end end + --- As of December 2014 the faster ``node.direct.*`` interface is --- preferred. -local nodedirect = nodes.nuts -local getchar = nodedirect.getchar + local getfont = nodedirect.getfont local getid = nodedirect.getid -local getnext = nodedirect.getnext -local getprev = nodedirect.getprev -local getfield = nodedirect.getfield -local setfield = nodedirect.setfield -local getsubtype = nodedirect.getsubtype + +local getnext = nodedirect.getnext or field_getter "next" +local setnext = nodedirect.setnext or field_setter "next" + +local getprev = nodedirect.getprev or field_getter "prev" +local setprev = nodedirect.setprev or field_setter "prev" + +local getdisc = nodedirect.getdisc or field_getter "disc" +local setdisc = nodedirect.setdisc or field_setter "disc" + +local getsubtype = nodedirect.getsubtype or field_getter "subtype" +local setsubtype = nodedirect.setsubtype or field_setter "subtype" + +local getchar = nodedirect.getchar or field_getter "subtype" +local setchar = nodedirect.setchar or field_setter "subtype" + local find_node_tail = nodedirect.tail local todirect = nodedirect.tonut local tonode = nodedirect.tonode @@ -310,10 +328,11 @@ kerncharacters = function (head) else --- c = kerncharacters (c) --> taken care of after replacing local s = start - local p, n = getprev(s), s.next + local p = getprev(s) + local n = getnext(s) local tail = find_node_tail(c) if p then - setfield(p, "next", c) + setnext(p, c) p = getprev(c) else head = c @@ -321,7 +340,7 @@ kerncharacters = function (head) if n then tail = getprev(n) end - setnext(tail, "next", n) + setnext(tail, n) start = c setfield(s, "components", nil) -- we now leak nodes ! @@ -368,7 +387,7 @@ kerncharacters = function (head) then -- keep else - prev_subtype = userkern_code + setsubtype (prev, userkern_code) local prev_kern = getfield(prev, "kern") prev_kern = prev_kern + quaddata[lastfont] * krn done = true @@ -395,24 +414,20 @@ kerncharacters = function (head) end elseif pid == disc_code then - -- a bit too complicated, we can best not copy and just calculate - -- but we could have multiple glyphs involved so ... local disc = prev -- disc - local pre = getfield(disc, "pre") - local post = getfield(disc, "post") - local replace = getfield(disc, "replace") - local prv = getprev(disc) - local nxt = getnext(disc) + local pre, post, replace = getdisc (disc) + local prv = getprev(disc) + local nxt = getnext(disc) if pre and prv then -- must pair with start.prev -- this one happens in most cases local before = copy_node(prv) - setfield(pre, "prev", before) - setfield(before, "next", pre) - setfield(before, "prev", nil) + setprev(pre, before) + setnext(before, pre) + setprev(before, nil) pre = kerncharacters (before) pre = getnext(pre) - setfield(pre, "prev", nil) + setprev(pre, nil) setfield(disc, "pre", pre) free_node(before) end @@ -420,11 +435,11 @@ kerncharacters = function (head) if post and nxt then -- must pair with start local after = copy_node(nxt) local tail = find_node_tail(post) - setfield(tail, "next", after) - setfield(after, "prev", tail) - setfield(after, "next", nil) + setnext(tail, after) + setprev(after, tail) + setnext(after, nil) post = kerncharacters (post) - setfield(tail, "next", nil) + setnext(tail, nil) setfield(disc, "post", post) free_node(after) end @@ -433,17 +448,17 @@ kerncharacters = function (head) local before = copy_node(prv) local after = copy_node(nxt) local tail = find_node_tail(replace) - setfield(replace, "prev", before) - setfield(before, "next", replace) - setfield(before, "prev", nil) - setfield(tail, "next", after) - setfield(after, "prev", tail) - setfield(after, "next", nil) + setprev(replace, before) + setnext(before, replace) + setprev(before, nil) + setnext(tail, after) + setprev(after, tail) + setnext(after, nil) replace = kerncharacters (before) replace = getnext(replace) - setfield(replace, "prev", nil) - setfield(getprev(after), "next", nil) - setfield(disc, "replace", replace) + setprev(replace, nil) + setnext(getprev(after), nil) + setfield(disc, "replace", replace) free_node(after) free_node(before) -- cgit v1.2.3 From 5ff0f91f3b18516d36ea2a800538cda552def336 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 21 Dec 2015 07:46:10 +0100 Subject: [letterspace] fix oversight in kern handling --- src/luaotfload-letterspace.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index f7c895f..0d6b8e8 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -390,6 +390,7 @@ kerncharacters = function (head) setsubtype (prev, userkern_code) local prev_kern = getfield(prev, "kern") prev_kern = prev_kern + quaddata[lastfont] * krn + setfield (prev, "kern", prev_kern) done = true end end -- cgit v1.2.3 From fde58ab447fbfdbf0eb07c627d3f3b789cf36759 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 21 Dec 2015 07:52:05 +0100 Subject: [features] conditionally pull in old feature mechanism Pretty hackish and probably not supported forever, but this is required on account of the changes to the loader since TL 2014. --- src/luaotfload-features.lua | 146 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 322a020..d212df5 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -970,7 +970,147 @@ local noflags = { } local tohash = table.tohash -local function addfeature(data,feature,specifications) +local function ancient_addfeature (data, feature, specifications) + local descriptions = data.descriptions + local resources = data.resources + local lookups = resources.lookups + local gsubfeatures = resources.features.gsub + if gsubfeatures and gsubfeatures[feature] then + -- already present + else + local sequences = resources.sequences + local fontfeatures = resources.features + local unicodes = resources.unicodes + local lookuptypes = resources.lookuptypes + local splitter = lpeg.splitter(" ",unicodes) + local done = 0 + local skip = 0 + if not specifications[1] then + -- so we accept a one entry specification + specifications = { specifications } + end + -- subtables are tables themselves but we also accept flattened singular subtables + for s=1,#specifications do + local specification = specifications[s] + local valid = specification.valid + if not valid or valid(data,specification,feature) then + local initialize = specification.initialize + if initialize then + -- when false is returned we initialize only once + specification.initialize = initialize(specification) and initialize or nil + end + local askedfeatures = specification.features or everywhere + local subtables = specification.subtables or { specification.data } or { } + local featuretype = types[specification.type or "substitution"] + local featureflags = specification.flags or noflags + local featureorder = specification.order or { feature } + local added = false + local featurename = stringformat("ctx_%s_%s",feature,s) + local st = { } + for t=1,#subtables do + local list = subtables[t] + local full = stringformat("%s_%s",featurename,t) + st[t] = full + if featuretype == "gsub_ligature" then + lookuptypes[full] = "ligature" + for code, ligature in next, list do + local unicode = tonumber(code) or unicodes[code] + local description = descriptions[unicode] + if description then + local slookups = description.slookups + if type(ligature) == "string" then + ligature = { lpegmatch(splitter,ligature) } + end + local present = true + for i=1,#ligature do + if not descriptions[ligature[i]] then + present = false + break + end + end + if present then + if slookups then + slookups[full] = ligature + else + description.slookups = { [full] = ligature } + end + done, added = done + 1, true + else + skip = skip + 1 + end + end + end + elseif featuretype == "gsub_single" then + lookuptypes[full] = "substitution" + for code, replacement in next, list do + local unicode = tonumber(code) or unicodes[code] + local description = descriptions[unicode] + if description then + local slookups = description.slookups + replacement = tonumber(replacement) or unicodes[replacement] + if descriptions[replacement] then + if slookups then + slookups[full] = replacement + else + description.slookups = { [full] = replacement } + end + done, added = done + 1, true + end + end + end + end + end + if added then + -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } + for k, v in next, askedfeatures do + if v[1] then + askedfeatures[k] = tabletohash(v) + end + end + local sequence = { + chain = 0, + features = { [feature] = askedfeatures }, + flags = featureflags, + name = featurename, + order = featureorder, + subtables = st, + type = featuretype, + } + if specification.prepend then + insert(sequences,1,sequence) + else + insert(sequences,sequence) + end + -- register in metadata (merge as there can be a few) + if not gsubfeatures then + gsubfeatures = { } + fontfeatures.gsub = gsubfeatures + end + local k = gsubfeatures[feature] + if not k then + k = { } + gsubfeatures[feature] = k + end + for script, languages in next, askedfeatures do + local kk = k[script] + if not kk then + kk = { } + k[script] = kk + end + for language, value in next, languages do + kk[language] = value + end + end + end + end + end + if trace_loading then + report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) + end + end +end + +local function current_addfeature(data,feature,specifications) local descriptions = data.descriptions local resources = data.resources local features = resources.features @@ -1344,6 +1484,10 @@ return { anum = anum_specification, } + --- hack for backwards compat with TL2014 loader + local addfeature = otf.version < 2.8 and current_addfeature + or ancient_addfeature + otf.enhancers.register ("check extra features", function (data, filename, raw) for feature, specification in next, extrafeatures do -- cgit v1.2.3