From 012786984e0f32a16f1153fc9f697e94992e4829 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 01:44:54 +0200 Subject: distinguish Xetex-style options; increment if indexed --- luaotfload-features.lua | 99 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 7ae035b..1635fba 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -9,6 +9,7 @@ if not modules then modules = { } end modules ["features"] = { local format, insert = string.format, table.insert local type, next = type, next local lpegmatch = lpeg.match +local mathceil = math.ceil ---[[ begin included font-ltx.lua ]] --- this appears to be based in part on luatex-fonts-def.lua @@ -877,22 +878,83 @@ end --doc]]-- -local strip_leading_sign = function (s) - --- handle option list keys - local first = stringsub(s, 1, 1) - if first == "+" or first == "-" then --- Xetex style - return stringsub(s, 2) +--local strip_leading_sign = function (s) +-- --- handle option list keys +-- local first = stringsub(s, 1, 1) +-- if first == "+" or first == "-" then --- Xetex style +-- return stringsub(s, 2) +-- end +-- return s +--end +-- +--local toboolean = function (s) +-- --- handle option list values +-- if s == "true" then return true end +-- if s == "false" then return false end +-- --if s == "yes" then return true end --- Context style +-- --if s == "no" then return false end +-- return stringlower(s) +--end + +local handle_normal_option = function (key, val) + val = stringlower(val) + --- the former “toboolean()” handler + if val == "true" then + val = true + elseif val == "false" then + val = false end - return s + return key, val end -local toboolean = function (s) - --- handle option list values - if s == "true" then return true end - if s == "false" then return false end - --if s == "yes" then return true end --- Context style - --if s == "no" then return false end - return stringlower(s) +--[[doc-- + + Xetex style indexing begins at zero which we just increment before + passing it along to the font loader. Ymmv. + + However, some non-indexed options expect scalars, so we cannot just + blindly add to *any* feature value. Instead we restrict it to those + features that are known to accept an index value, for instance GSUB + lookup type 3 ones like “ssty”. + + http://partners.adobe.com/public/developer/opentype/index_table_formats1.html#ASF1 + +--doc]]-- + +local indexed_features = table.tohash ({ + --- Note that this list is not definitive and was gathered by + --- grepping Adobe’s feature tag spec. + "aalt", + "cswh", + "curs", + "falt", + "hngl", + "jalt", + "jp78", + "nalt", + "ornm", + "rand", + "rlig", + "salt", + "ssty", + "swsh", + "trad", +}, true) + +local handle_xetex_option = function (key, val) + local numeric = tonumber(val) --- decimal only; keeps colors intact + if numeric then --- ugh + if mathceil(numeric) == numeric -- integer, possible index + and indexed_features[key] + then + val = tostring(numeric + 1) + end + elseif val == "true" then + val = true + elseif val == "false" then + val = false + end + return key, val end --[[doc-- @@ -977,10 +1039,15 @@ local path_lookup = lbrk * Cg(C((1-rbrk)^1), "path") * rbrk --- features ---------------------------------------------------------- local field = (anum + S"+-.")^1 --- sic! --- assignments are “lhs=rhs” +--- or “+lhs=rhs” (Xetex-style) --- switches are “+key” | “-key” -local assignment = (field / strip_leading_sign) * ws - * equals * ws - * (field / toboolean) +local normal_option = C(field) * ws * equals * ws * C(field) * ws +local xetex_option = P"+" * ws * normal_option +local assignment = xetex_option / handle_xetex_option + + normal_option / handle_normal_option +----- assignment = (field / strip_leading_sign) * ws +----- * equals * ws +----- * (field / toboolean) local switch = P"+" * ws * C(field) * Cc(true) + P"-" * ws * C(field) * Cc(false) + C(field) * Cc(true) -- catch crap -- cgit v1.2.3 From ba2d7155dfd46e432da4ef9888d7ca1dc530246e Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 01:47:15 +0200 Subject: cleanup features --- luaotfload-features.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 1635fba..52d947e 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -6,10 +6,10 @@ if not modules then modules = { } end modules ["features"] = { license = "see context related readme files" } -local format, insert = string.format, table.insert local type, next = type, next +local tonumber = tonumber +local tostring = tostring local lpegmatch = lpeg.match -local mathceil = math.ceil ---[[ begin included font-ltx.lua ]] --- this appears to be based in part on luatex-fonts-def.lua @@ -29,15 +29,15 @@ function fonts.definers.getspecification(str) return "", str, "", ":", str end -local old_feature_list = { } - local report = logs.names_report local stringfind = string.find local stringlower = string.lower local stringgsub = string.gsub local stringsub = string.sub +local stringformat = string.format local stringis_empty = string.is_empty +local mathceil = math.ceil --- TODO an option to dump the default features for a script would make --- a nice addition to luaotfload-tool @@ -1298,11 +1298,11 @@ local function addfeature(data,feature,specifications) local featuretype = types[specification.type or "substitution"] local featureflags = specification.flags or noflags local added = false - local featurename = format("ctx_%s_%s",feature,s) + local featurename = stringformat("ctx_%s_%s",feature,s) local st = { } for t=1,#subtables do local list = subtables[t] - local full = format("%s_%s",featurename,t) + local full = stringformat("%s_%s",featurename,t) st[t] = full if featuretype == "gsub_ligature" then lookuptypes[full] = "ligature" -- cgit v1.2.3 From d904df22170aff308c2b3ebada4fcbb29be85af1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 12:00:26 +0200 Subject: =?UTF-8?q?skip=20unusable=20option=20fields;=20remove=20test=20fo?= =?UTF-8?q?r=20supposedly=20=E2=80=9Cindexed=E2=80=9D=20features?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaotfload-features.lua | 62 +++++++------------------------------------------ 1 file changed, 9 insertions(+), 53 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 52d947e..b4ad9c9 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -878,24 +878,6 @@ end --doc]]-- ---local strip_leading_sign = function (s) --- --- handle option list keys --- local first = stringsub(s, 1, 1) --- if first == "+" or first == "-" then --- Xetex style --- return stringsub(s, 2) --- end --- return s ---end --- ---local toboolean = function (s) --- --- handle option list values --- if s == "true" then return true end --- if s == "false" then return false end --- --if s == "yes" then return true end --- Context style --- --if s == "no" then return false end --- return stringlower(s) ---end - local handle_normal_option = function (key, val) val = stringlower(val) --- the former “toboolean()” handler @@ -912,41 +894,13 @@ end Xetex style indexing begins at zero which we just increment before passing it along to the font loader. Ymmv. - However, some non-indexed options expect scalars, so we cannot just - blindly add to *any* feature value. Instead we restrict it to those - features that are known to accept an index value, for instance GSUB - lookup type 3 ones like “ssty”. - - http://partners.adobe.com/public/developer/opentype/index_table_formats1.html#ASF1 - --doc]]-- -local indexed_features = table.tohash ({ - --- Note that this list is not definitive and was gathered by - --- grepping Adobe’s feature tag spec. - "aalt", - "cswh", - "curs", - "falt", - "hngl", - "jalt", - "jp78", - "nalt", - "ornm", - "rand", - "rlig", - "salt", - "ssty", - "swsh", - "trad", -}, true) - local handle_xetex_option = function (key, val) + val = stringlower(val) local numeric = tonumber(val) --- decimal only; keeps colors intact if numeric then --- ugh - if mathceil(numeric) == numeric -- integer, possible index - and indexed_features[key] - then + if mathceil(numeric) == numeric then -- integer, possible index val = tostring(numeric + 1) end elseif val == "true" then @@ -1037,7 +991,8 @@ local unprefixed = Cg(fontname, "anon") local path_lookup = lbrk * Cg(C((1-rbrk)^1), "path") * rbrk --- features ---------------------------------------------------------- -local field = (anum + S"+-.")^1 --- sic! +local field_char = anum + S"+-." --- sic! +local field = field_char^1 --- assignments are “lhs=rhs” --- or “+lhs=rhs” (Xetex-style) --- switches are “+key” | “-key” @@ -1050,11 +1005,13 @@ local assignment = xetex_option / handle_xetex_option ----- * (field / toboolean) local switch = P"+" * ws * C(field) * Cc(true) + P"-" * ws * C(field) * Cc(false) - + C(field) * Cc(true) -- catch crap +-- + C(field) * Cc(true) -- catch crap +local ignore = (1 - featuresep)^1 --- ignores one option local feature_expr = ws * Cg(assignment + switch) * ws +local option = feature_expr + ignore local feature_list = Cf(Ct"" - * feature_expr - * (featuresep * feature_expr)^0 + * option + * (featuresep * option)^0 , rawset) * featuresep^-1 @@ -1069,7 +1026,6 @@ local feature_list = Cf(Ct"" --- string; I won’t mess with it though until someone reports a --- problem.) --- local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim ---- Who’s Kim? --- Note to self: subfonts apparently start at index 0. Tested with --- Cambria.ttc that includes “Cambria Math” at 0 and “Cambria” at 1. --- Other values cause luatex to segfault. -- cgit v1.2.3 From bb65ba28ea757225f9bb5707c631e8444db5954e Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 13:34:01 +0200 Subject: emit warning for invalid font request options --- luaotfload-features.lua | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index b4ad9c9..415d2ac 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -754,6 +754,7 @@ local support_incomplete = table.tohash({ --- (string, string) dict -> (string, string) dict local set_default_features = function (speclist) speclist = speclist or { } + speclist[""] = nil --- invalid options stub --- handle language tag local language = speclist.language @@ -911,6 +912,22 @@ local handle_xetex_option = function (key, val) return key, val end +--[[doc-- + + Instead of silently ignoring invalid options we emit a warning to + the log. + + Note that we have to return a pair to please rawset(). This creates + an entry on the resulting features hash which will later be removed + during set_default_features(). + +--doc]]-- + +local handle_invalid_option = function (opt) + report("log", 0, "load", "font option “%s” unknown.", opt) + return "", false +end + --[[doc-- Dirty test if a file: request is actually a path: lookup; don’t @@ -1006,7 +1023,8 @@ local assignment = xetex_option / handle_xetex_option local switch = P"+" * ws * C(field) * Cc(true) + P"-" * ws * C(field) * Cc(false) -- + C(field) * Cc(true) -- catch crap -local ignore = (1 - featuresep)^1 --- ignores one option +local ignore = (1 - featuresep)^1 --- ignores one option + / handle_invalid_option local feature_expr = ws * Cg(assignment + switch) * ws local option = feature_expr + ignore local feature_list = Cf(Ct"" @@ -1136,8 +1154,8 @@ local handle_request = function (specification) specification.lookup = "path" return specification end - local lookup, name = select_lookup(request) - request.features = set_default_features(request.features) + local lookup, name = select_lookup(request) + request.features = set_default_features(request.features) if name then specification.name = name -- cgit v1.2.3 From 1489b66525103c3762ac1f3dea63214db01a798c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 20:08:26 +0200 Subject: add font-dependent letterspacing --- luaotfload-letterspace.lua | 254 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 luaotfload-letterspace.lua diff --git a/luaotfload-letterspace.lua b/luaotfload-letterspace.lua new file mode 100644 index 0000000..fabf62b --- /dev/null +++ b/luaotfload-letterspace.lua @@ -0,0 +1,254 @@ +if not modules then modules = { } end modules ['typo-krn'] = { + version = 1.001, + comment = "companion to typo-krn.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next = next +local nodes, node, fonts = nodes, node, fonts + +local find_node_tail = node.tail or node.slide +local free_node = node.free +local free_nodelist = node.flush_list +local copy_node = node.copy +local copy_nodelist = node.copy_list +local insert_node_before = node.insert_before +local insert_node_after = node.insert_after + +local nodepool = nodes.pool +local tasks = nodes.tasks + +local new_kern = nodepool.kern +local new_glue = nodepool.glue + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes +local skipcodes = nodes.skipcodes + +local glyph_code = nodecodes.glyph +local kern_code = nodecodes.kern +local disc_code = nodecodes.disc +local glue_code = nodecodes.glue +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local math_code = nodecodes.math + +local kerning_code = kerncodes.kerning +local userkern_code = kerncodes.userkern + +local fonthashes = fonts.hashes +local chardata = fonthashes.characters +local quaddata = fonthashes.quads + +typesetters = typesetters or { } +local typesetters = typesetters + +typesetters.kernfont = typesetters.kernfont or { } +local kernfont = typesetters.kernfont + +kernfont.keepligature = false +kernfont.keeptogether = false + +local kern_injector = function (fillup,kern) + if fillup then + local g = new_glue(kern) + local s = g.spec + s.stretch = kern + s.stretch_order = 1 + return g + else + return new_kern(kern) + end +end + +local kernfactors = { } --- fontid -> factor + +local kerncharacters +kerncharacters = function (head) + local start, done = head, false + local lastfont = nil + local keepligature = kernfont.keepligature --- function + local keeptogether = kernfont.keeptogether --- function + local fillup = false + + local identifiers = fonthashes.identifiers + local kernfactors = kernfactors + + while start do + local attr = start[attribute] + local id = start.id + if id == glyph_code then + + --- 1) look up kern factor (slow, but cached rudimentarily) + local krn + local fontid = start.font + do + krn = kernfactors[fontid] + if not krn then + local tfmdata = identifiers[fontid] + if not tfmdata then -- unsafe + tfmdata = font.fonts[fontid] + end + if tfmdata then + fontproperties = tfmdata.properties + if fontproperties then + krn = fontproperties.kerncharacters + end + end + kernfactors[fontid] = krn + end + if not krn or krn == 0 then + goto nextnode + end + end + + if krn == "max" then + krn = .25 + fillup = true + else + fillup = false + end + + lastfont = fontid + local c = start.components + + if c then + if keepligature and keepligature(start) then + -- keep 'm + else + c = kerncharacters (c) + local s = start + local p, n = s.prev, s.next + local tail = find_node_tail(c) + if p then + p.next = c + c.prev = p + else + head = c + end + if n then + n.prev = tail + end + tail.next = n + start = c + s.components = nil + -- we now leak nodes ! + -- free_node(s) + done = true + end + end -- kern ligature + + local prev = start.prev + if prev then + local pid = prev.id + + if not pid then + -- nothing + elseif pid == kern_code then + if prev.subtype == kerning_code or prev[a_fontkern] then + if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then -- we could also pass start + -- keep 'm + else + -- not yet ok, as injected kerns can be overlays (from node-inj.lua) + prev.subtype = userkern_code + prev.kern = prev.kern + quaddata[lastfont]*krn -- here + done = true + end + end + elseif pid == glyph_code then + if prev.font == lastfont then + local prevchar, lastchar = prev.char, start.char + if keeptogether and keeptogether(prev,start) then + -- keep 'm + elseif identifiers[lastfont] then + local kerns = chardata[lastfont][prevchar].kerns + local kern = kerns and kerns[lastchar] or 0 + krn = kern + quaddata[lastfont]*krn -- here + insert_node_before(head,start,kern_injector(fillup,krn)) + done = true + end + else + krn = quaddata[lastfont]*krn -- here + insert_node_before(head,start,kern_injector(fillup,krn)) + done = true + 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, post, replace = disc.pre, disc.post, disc.replace + local prv, nxt = disc.prev, disc.next + + if pre and prv then -- must pair with start.prev + -- this one happens in most cases + local before = copy_node(prv) + pre.prev = before + before.next = pre + before.prev = nil + pre = kerncharacters (before) + pre = pre.next + pre.prev = nil + disc.pre = pre + free_node(before) + end + + if post and nxt then -- must pair with start + local after = copy_node(nxt) + local tail = find_node_tail(post) + tail.next = after + after.prev = tail + after.next = nil + post = kerncharacters (post) + tail.next = nil + disc.post = post + free_node(after) + end + + if replace and prv and nxt then -- must pair with start and start.prev + local before = copy_node(prv) + local after = copy_node(nxt) + local tail = find_node_tail(replace) + replace.prev = before + before.next = replace + before.prev = nil + tail.next = after + after.prev = tail + after.next = nil + replace = kerncharacters (before) + replace = replace.next + replace.prev = nil + after.prev.next = nil + disc.replace = replace + free_node(after) + free_node(before) + elseif identifiers[lastfont] then + if prv and prv.id == glyph_code and prv.font == lastfont then + local prevchar, lastchar = prv.char, start.char + local kerns = chardata[lastfont][prevchar].kerns + local kern = kerns and kerns[lastchar] or 0 + krn = kern + quaddata[lastfont]*krn -- here + else + krn = quaddata[lastfont]*krn -- here + end + disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue + end + + end + end + end + + ::nextnode:: + if start then + start = start.next + end + end + return head, done +end + +kernfont.handler = kerncharacters + +--- vim:sw=2:ts=2:expandtab + -- cgit v1.2.3 From 942f76c831da1ba5a85ce5b77374f2315caa768b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 20:09:13 +0200 Subject: adapt extralib --- luaotfload-extralibs.lua | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/luaotfload-extralibs.lua b/luaotfload-extralibs.lua index 618808f..f6ba607 100644 --- a/luaotfload-extralibs.lua +++ b/luaotfload-extralibs.lua @@ -207,6 +207,7 @@ if not markdata then fonthashes.marks = markdata end +--- next stems from the multilingual interface interfaces = interfaces or { } interfaces.variables = interfaces.variables or { } interfaces.variables.max = "max" @@ -283,7 +284,8 @@ commands = commands or { } --- we should be ready at this moment to insert the library -require "luaotfload-typo-krn" +--require "luaotfload-typo-krn" +require "luaotfload-letterspace" --- simplified --===================================================================-- --- CLEAN @@ -296,6 +298,8 @@ local mapping = kerns.mapping local unsetvalue = attributes.unset_value local process_kerns = plugin_store.kern +local kernfont = typesetters.kernfont + local kerncharacters = function (head) return process_kerns("kerns", hidden.a_kerns, head) end @@ -304,52 +308,60 @@ end local add_kern_processor = function (...) for i=1, select("#", ...) do luatexbase.add_to_callback( - select(i, ...), kerncharacters, callback_name + select(i, ...), kernfont.handler, callback_name ) end end local remove_kern_processor = function (...) for i=1, select("#", ...) do luatexbase.remove_from_callback( - select(i, ...), kerncharacters, callback_name + select(i, ...), callback_name ) end end --- we use the same callbacks as a node processor in Context -kerns.enablecharacterkerning = function ( ) +local enablecharacterkerning = function ( ) add_kern_processor("pre_linebreak_filter", "hpack_filter") end -kerns.disablecharacterkerning = function ( ) +local disablecharacterkerning = function ( ) remove_kern_processor("pre_linebreak_filter", "hpack_filter") end +--kerns.enablecharacterkerning = enablecharacterkerning +--kerns.disablecharacterkerning = disablecharacterkerning +kernfont.enablecharacterkerning = enablecharacterkerning +kernfont.disablecharacterkerning = disablecharacterkerning + local enabled = false --- callback state ---- we just replace the kern enabler with our modified version -kerns.set = function (factor) - if factor ~= v_max then +local initializekerning = function (tfmdata, factor) + if factor ~= "max" then factor = tonumber(factor) or 0 end - if factor == v_max or factor ~= 0 then + if factor == "max" or factor ~= 0 then + local fontproperties = tfmdata.properties + if fontproperties then + --- hopefully this field stays unused otherwise + fontproperties.kerncharacters = factor + end if not enabled then - kerns.enablecharacterkerning() + enablecharacterkerning() enabled = true end - local a = factors[factor] - if not a then - a = #mapping + 1 - factors[factors], mapping[a] = a, factor - end - factor = a - else - factor = unsetvalue end - texattribute[hidden.a_kerns] = factor - return factor end +local otffeatures = fonts.constructors.newfeatures "otf" +otffeatures.register { + name = "kerncharacters", + description = "kerncharacters", + initializers = { + base = initializekerning, + node = initializekerning, + } +} ----------------------------------------------------------------------- --- options -- cgit v1.2.3 From 7c5c6c9e3ebc613c97a18e26f08de1c855b1d77b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 20:23:00 +0200 Subject: add comments and a disclaimer regarding letterspacing --- luaotfload-letterspace.lua | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/luaotfload-letterspace.lua b/luaotfload-letterspace.lua index fabf62b..ef41bb6 100644 --- a/luaotfload-letterspace.lua +++ b/luaotfload-letterspace.lua @@ -1,7 +1,7 @@ -if not modules then modules = { } end modules ['typo-krn'] = { - version = 1.001, - comment = "companion to typo-krn.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +if not modules then modules = { } end modules ['letterspace'] = { + version = 2.200, + comment = "companion to luaotfload.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } @@ -63,6 +63,19 @@ local kern_injector = function (fillup,kern) end end +--[[doc-- + + Caveat lector. + This is a preliminary, makeshift adaptation of the Context + character kerning mechanism that emulates XeTeX-style fontwise + letterspacing. Note that in its present state it is far inferior to + the original, which is attribute-based and ignores font-boundaries. + Nevertheless, due to popular demand the following callback has been + added. It should not be relied upon to be present in future + versions. + +--doc]]-- + local kernfactors = { } --- fontid -> factor local kerncharacters @@ -112,8 +125,9 @@ kerncharacters = function (head) end lastfont = fontid - local c = start.components + --- 2) resolve ligatures + local c = start.components if c then if keepligature and keepligature(start) then -- keep 'm @@ -140,23 +154,25 @@ kerncharacters = function (head) end end -- kern ligature + --- 3) apply the extra kerning local prev = start.prev if prev then local pid = prev.id if not pid then -- nothing + elseif pid == kern_code then if prev.subtype == kerning_code or prev[a_fontkern] then - if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then -- we could also pass start - -- keep 'm + if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then + -- keep else - -- not yet ok, as injected kerns can be overlays (from node-inj.lua) prev.subtype = userkern_code prev.kern = prev.kern + quaddata[lastfont]*krn -- here done = true end end + elseif pid == glyph_code then if prev.font == lastfont then local prevchar, lastchar = prev.char, start.char @@ -250,5 +266,5 @@ end kernfont.handler = kerncharacters ---- vim:sw=2:ts=2:expandtab +--- vim:sw=2:ts=2:expandtab:tw=71 -- cgit v1.2.3 From ddf5bd917a05f5826e47f87d128d1948d0c4e49c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 19 May 2013 21:07:46 +0200 Subject: reinstate characterkerning --- luaotfload-extralibs.lua | 150 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 39 deletions(-) diff --git a/luaotfload-extralibs.lua b/luaotfload-extralibs.lua index f6ba607..1e0d85a 100644 --- a/luaotfload-extralibs.lua +++ b/luaotfload-extralibs.lua @@ -23,6 +23,7 @@ local texattribute = tex.attribute local new_node = node.new local copy_node = node.copy +local otffeatures = fonts.constructors.newfeatures "otf" ----------------------------------------------------------------------- --- namespace @@ -38,8 +39,10 @@ local kerns = typesetters.kerns kerns.mapping = kerns.mapping or { } kerns.factors = kerns.factors or { } -local namespace = "kern" --- <= attribute <= plugin.name -local callback_name = "typesetters.kerncharacters" +local kern_callback = "typesetters.kerncharacters" + +typesetters.kernfont = typesetters.kernfont or { } +local kernfont = typesetters.kernfont ----------------------------------------------------------------------- --- node-ini @@ -282,10 +285,10 @@ commands = commands or { } --- LOAD --===================================================================-- ---- we should be ready at this moment to insert the library +--- we should be ready at this moment to insert the libraries ---require "luaotfload-typo-krn" -require "luaotfload-letterspace" --- simplified +require "luaotfload-typo-krn" --- typesetters.kerns +require "luaotfload-letterspace" --- typesetters.kernfont --===================================================================-- --- CLEAN @@ -298,45 +301,83 @@ local mapping = kerns.mapping local unsetvalue = attributes.unset_value local process_kerns = plugin_store.kern -local kernfont = typesetters.kernfont +--- kern_callback : normal +--- · callback: process_kerns +--- · enabler: enablecharacterkerning +--- · disabler: disablecharacterkerning +--- · interface: kerns.set -local kerncharacters = function (head) - return process_kerns("kerns", hidden.a_kerns, head) -end +--- kernfont_callback : fontwise +--- · callback: kernfont.handler +--- · enabler: enablefontkerning +--- · disabler: disablefontkerning --- callback wrappers -local add_kern_processor = function (...) - for i=1, select("#", ...) do - luatexbase.add_to_callback( - select(i, ...), kernfont.handler, callback_name - ) + +--- (node_t -> node_t) -> string -> string list -> bool +local registered_as = { } --- procname -> callbacks +local add_processor = function (processor, name, ...) + local callbacks = { ... } + for i=1, #callbacks do + luatexbase.add_to_callback(callbacks[i], processor, name) end + registered_as[name] = callbacks --- for removal + return true end -local remove_kern_processor = function (...) - for i=1, select("#", ...) do - luatexbase.remove_from_callback( - select(i, ...), callback_name - ) + +--- string -> bool +local remove_processor = function (name) + local callbacks = registered_as[name] + if callbacks then + for i=1, #callbacks do + luatexbase.remove_from_callback(callbacks[i], name) + end + return true end + return false --> unregistered end --- we use the same callbacks as a node processor in Context +--- unit -> bool local enablecharacterkerning = function ( ) - add_kern_processor("pre_linebreak_filter", "hpack_filter") + return add_processor(function (head) + return process_kerns("kerns", hidden.a_kerns, head) + end, + "typesetters.kerncharacters", + "pre_linebreak_filter", "hpack_filter" + ) end +--- unit -> bool local disablecharacterkerning = function ( ) - remove_kern_processor("pre_linebreak_filter", "hpack_filter") + return remove_processor "typesetters.kerncharacters" end ---kerns.enablecharacterkerning = enablecharacterkerning ---kerns.disablecharacterkerning = disablecharacterkerning -kernfont.enablecharacterkerning = enablecharacterkerning -kernfont.disablecharacterkerning = disablecharacterkerning +kerns.enablecharacterkerning = enablecharacterkerning +kerns.disablecharacterkerning = disablecharacterkerning + +--- now for the simplistic variant +--- unit -> bool +local enablefontkerning = function ( ) + return add_processor( + kernfont.handler, + "typesetters.kernfont", + "pre_linebreak_filter", "hpack_filter" + ) +end + +--- unit -> bool +local disablefontkerning = function ( ) + return remove_processor "typesetters.kernfont" +end -local enabled = false --- callback state +--- fontwise kerning uses a font property for passing along the +--- letterspacing factor -local initializekerning = function (tfmdata, factor) +local fontkerning_enabled = false --- callback state + +--- fontobj -> float -> unit +local initializefontkerning = function (tfmdata, factor) if factor ~= "max" then factor = tonumber(factor) or 0 end @@ -346,29 +387,60 @@ local initializekerning = function (tfmdata, factor) --- hopefully this field stays unused otherwise fontproperties.kerncharacters = factor end - if not enabled then - enablecharacterkerning() - enabled = true + if not fontkerning_enabled then + fontkerning_enabled = enablefontkerning() end end end -local otffeatures = fonts.constructors.newfeatures "otf" +--- like the font colorization, fontwise kerning is hooked into the +--- feature mechanism + otffeatures.register { - name = "kerncharacters", - description = "kerncharacters", - initializers = { - base = initializekerning, - node = initializekerning, - } + name = "letterspace", --"kerncharacters", + description = "letterspace", --"kerncharacters", + initializers = { + base = initializefontkerning, + node = initializefontkerning, + } } +kerns.set = nil + +local characterkerning_enabled = false + +kerns.set = function (factor) + if factor ~= "max" then + factor = tonumber(factor) or 0 + end + if factor == "max" or factor ~= 0 then + if not characterkerning_enabled then + enablecharacterkerning() + characterkerning_enabled = true + end + local a = factors[factor] + if not a then + a = #mapping + 1 + factors[factors], mapping[a] = a, factor + end + factor = a + else + factor = unsetvalue + end + texattribute[hidden.a_kerns] = factor + return factor +end + + + ----------------------------------------------------------------------- --- options ----------------------------------------------------------------------- -kerns.keepligature = false --- supposed to be of type function -kerns.keeptogether = false --- supposed to be of type function +kerns .keepligature = false --- supposed to be of type function +kerns .keeptogether = false --- supposed to be of type function +kernfont.keepligature = false --- supposed to be of type function +kernfont.keeptogether = false --- supposed to be of type function ----------------------------------------------------------------------- --- erase fake Context layer -- cgit v1.2.3