From 7d25823db5c96e6877dd74158bb9847ec2666268 Mon Sep 17 00:00:00 2001 From: Context Git Mirror Bot Date: Mon, 8 Dec 2014 23:15:04 +0100 Subject: 2014-12-08 22:17:00 --- tex/context/base/cont-new.mkiv | 2 +- tex/context/base/context-version.pdf | Bin 4389 -> 4387 bytes tex/context/base/context.mkiv | 2 +- tex/context/base/font-ota.lua | 4 +- tex/context/base/lang-hyp.lua | 7 +- tex/context/base/node-fnt.lua | 100 +++++- tex/context/base/node-pro.lua | 6 +- tex/context/base/node-tex.lua | 38 +-- tex/context/base/status-files.pdf | Bin 24645 -> 24652 bytes tex/context/base/status-lua.pdf | Bin 344542 -> 344593 bytes tex/context/base/task-ini.lua | 20 +- tex/context/base/typo-cap.lua | 349 +++++++++++---------- tex/context/base/typo-cap.mkiv | 9 +- tex/context/base/typo-itc.lua | 318 ++++++++++++++----- tex/context/base/typo-krn.lua | 46 +-- tex/generic/context/luatex/luatex-fonts-cbk.lua | 53 +++- tex/generic/context/luatex/luatex-fonts-merged.lua | 46 ++- 17 files changed, 677 insertions(+), 323 deletions(-) (limited to 'tex') diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 532ace65a..0c4bd8612 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2014.12.06 14:20} +\newcontextversion{2014.12.08 22:14} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf index a5639e8be..44daebfd8 100644 Binary files a/tex/context/base/context-version.pdf and b/tex/context/base/context-version.pdf differ diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 063ea144a..da307b178 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -28,7 +28,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2014.12.06 14:20} +\edef\contextversion{2014.12.08 22:14} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua index 9db52a3c5..1f1534870 100644 --- a/tex/context/base/font-ota.lua +++ b/tex/context/base/font-ota.lua @@ -143,7 +143,9 @@ function analyzers.setstate(head,font) -- we can skip math first, last, n = nil, nil, 0 end elseif id == disc_code then - -- always in the middle + -- always in the middle .. it doesn't make much sense to assign a property + -- here ... we might at some point decide to flag the components when present + -- but even then it's kind of bogus setprop(current,a_state,s_medi) last = current else -- finish diff --git a/tex/context/base/lang-hyp.lua b/tex/context/base/lang-hyp.lua index 58a8bffcf..d6217857b 100644 --- a/tex/context/base/lang-hyp.lua +++ b/tex/context/base/lang-hyp.lua @@ -160,9 +160,12 @@ local function unregister_pattern(patterns,specials,str) specials[k] = nil end +local p_lower = lpeg.patterns.utf8lower + local function register_exception(exceptions,str,specification) - local k = lpegmatch(make_hashkey_e,str) - local v = lpegmatch(make_pattern_e,str) + local l = lpegmatch(p_lower,str) + local k = lpegmatch(make_hashkey_e,l) + local v = lpegmatch(make_pattern_e,l) exceptions[k] = v end diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua index 0ab0867dc..1dd944403 100644 --- a/tex/context/base/node-fnt.lua +++ b/tex/context/base/node-fnt.lua @@ -13,8 +13,11 @@ local concat, keys = table.concat, table.keys local nodes, node, fonts = nodes, node, fonts -local trace_characters = false trackers.register("nodes.characters", function(v) trace_characters = v end) -local trace_fontrun = false trackers.register("nodes.fontrun", function(v) trace_fontrun = v end) +local trace_characters = false trackers .register("nodes.characters", function(v) trace_characters = v end) +local trace_fontrun = false trackers .register("nodes.fontrun", function(v) trace_fontrun = v end) + +local force_discrun = true directives.register("nodes.discrun", function(v) force_discrun = v end) +local force_basepass = true directives.register("nodes.basepass", function(v) force_basepass = v end) local report_fonts = logs.reporter("fonts","processing") @@ -117,14 +120,22 @@ fonts.hashes.processes = fontprocesses -- we need to deal with the basemode fonts here and can only run over ranges as we -- otherwise get luatex craches due to all kind of asserts in the disc/lig builder -local ligaturing = builders.kernel.ligaturing -local kerning = builders.kernel.kerning +local ligaturing = node.ligaturing +local kerning = node.kerning function handlers.characters(head) -- either next or not, but definitely no already processed list starttiming(nodes) - local usedfonts, attrfonts, basefonts = { }, { }, { } - local a, u, b, prevfont, prevattr, done, basefont = 0, 0, 0, nil, 0, false, nil + + local usedfonts = { } + local attrfonts = { } + local basefonts = { } + local a, u, b = 0, 0, 0 + local basefont = nil + local prevfont = nil + local prevattr = 0 + local done = false + if trace_fontrun then run = run + 1 report_fonts() @@ -145,7 +156,10 @@ function handlers.characters(head) n = getnext(n) end end - for n in traverse_id(glyph_code,tonut(head)) do + + local nuthead = tonut(head) + + for n in traverse_id(glyph_code,nuthead) do if getsubtype(n) < 256 then -- all are 1 local font = getfont(n) local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context @@ -164,7 +178,7 @@ function handlers.characters(head) if fd then used[attr] = fd[attr] a = a + 1 - else + elseif force_basepass then b = b + 1 basefont = { tonode(n), nil } basefonts[b] = basefont @@ -177,7 +191,7 @@ function handlers.characters(head) if fp then usedfonts[font] = fp u = u + 1 - else + elseif force_basepass then b = b + 1 basefont = { tonode(n), nil } basefonts[b] = basefont @@ -188,8 +202,63 @@ function handlers.characters(head) prevattr = attr end end - -- end end + + -- could be an optional pass : seldom needed, only for documentation as a discretionary + -- with pre/post/replace will normally not occur on it's own + + if force_discrun then + + -- basefont is not supported in disc only runs ... it would mean a lot of + -- ranges .. we could try to run basemode as a separate processor run but + -- not for now (we can consider it when the new node code is tested + + -- local prevfont = nil + -- local prevattr = 0 + + for d in traverse_id(disc_code,nuthead) do + -- we could use first_glyph + local r = getfield(n,"replace") -- good enough + if r then + for n in traverse_id(glyph_code,r) do + if getsubtype(n) < 256 then -- all are 1 + local font = getfont(n) + local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + if font ~= prevfont or attr ~= prevattr then + if attr > 0 then + local used = attrfonts[font] + if not used then + used = { } + attrfonts[font] = used + end + if not used[attr] then + local fd = setfontdynamics[font] + if fd then + used[attr] = fd[attr] + a = a + 1 + end + end + else + local used = usedfonts[font] + if not used then + local fp = fontprocesses[font] + if fp then + usedfonts[font] = fp + u = u + 1 + end + end + end + prevfont = font + prevattr = attr + end + end + break + end + end + end + + end + if trace_fontrun then report_fonts() report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none") @@ -249,11 +318,18 @@ function handlers.characters(head) if b == 0 then -- skip elseif b == 1 then + -- only one font local range = basefonts[1] local start, stop = range[1], range[2] - ligaturing(start,stop) - kerning(start,stop) + if stop then + ligaturing(start,stop) + kerning(start,stop) + else + ligaturing(start) + kerning(start) + end else + -- multiple fonts for i=1,b do local range = basefonts[i] local start, stop = range[1], range[2] diff --git a/tex/context/base/node-pro.lua b/tex/context/base/node-pro.lua index 2cc00601c..27e349893 100644 --- a/tex/context/base/node-pro.lua +++ b/tex/context/base/node-pro.lua @@ -55,7 +55,7 @@ do return concat(t) end - local function tracer(what,state,head,groupcode,before,after,show) + function processors.tracer(what,state,head,groupcode,before,after,show) if not groupcode then groupcode = "unknown" elseif groupcode == "" then @@ -69,10 +69,10 @@ do end end - processors.tracer = tracer - end +local tracer = processors.tracer + processors.enabled = true -- this will become a proper state (like trackers) function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction diff --git a/tex/context/base/node-tex.lua b/tex/context/base/node-tex.lua index 9f6df031b..8f4a65450 100644 --- a/tex/context/base/node-tex.lua +++ b/tex/context/base/node-tex.lua @@ -6,37 +6,33 @@ if not modules then modules = { } end modules ['node-tex'] = { license = "see context related readme files" } -local format = string.format +builders = builders or { } +local kernel = builders.kernel or { } +builders.kernel = kernel -builders = builders or { } -builders.kernel = builders.kernel or { } -local kernel = builders.kernel +local hyphenate = lang.hyphenate +local ligaturing = node.ligaturing +local kerning = node.kerning -local hyphenate, ligaturing, kerning = lang.hyphenate, node.ligaturing, node.kerning +kernel.originals = { + hyphenate = hyphenate, + ligaturing = ligaturing, + kerning = kerning, +} function kernel.hyphenation(head) local done = hyphenate(head) return head, done end -function kernel.ligaturing(head,tail) - if tail then - local head, tail, done = ligaturing(head,tail) - return head, done - else -- sensitive for second arg nil - local head, tail, done = ligaturing(head) - return head, done - end +function kernel.ligaturing(head) + local head, tail, done = ligaturing(head) + return head, done end -function kernel.kerning(head,tail) - if tail then - local head, tail, done = kerning(head,tail) - return head, done - else -- sensitive for second arg nil - local head, tail, done = kerning(head) - return head, done - end +function kernel.kerning(head) + local head, tail, done = kerning(head) + return head, done end callbacks.register('hyphenate' , false, "normal hyphenation routine, called elsewhere") diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf index efc5834d0..d32c3dc6c 100644 Binary files a/tex/context/base/status-files.pdf and b/tex/context/base/status-files.pdf differ diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf index 832bbf225..68290ae02 100644 Binary files a/tex/context/base/status-lua.pdf and b/tex/context/base/status-lua.pdf differ diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua index 3db0c2d6e..4087caafe 100644 --- a/tex/context/base/task-ini.lua +++ b/tex/context/base/task-ini.lua @@ -21,6 +21,7 @@ local tasks = nodes.tasks local prependaction = tasks.prependaction local appendaction = tasks.appendaction local disableaction = tasks.disableaction +local enableaction = tasks.enableaction local freezegroup = tasks.freezegroup local freezecallbacks = callbacks.freeze @@ -48,8 +49,8 @@ appendaction("processors", "fonts", "builders.paragraphs.solutions.split appendaction("processors", "fonts", "nodes.handlers.characters") -- maybe todo appendaction("processors", "fonts", "nodes.injections.handler") -- maybe todo appendaction("processors", "fonts", "nodes.handlers.protectglyphs", nil, "nohead") -- maybe todo -------------("processors", "fonts", "builders.kernel.ligaturing") -- always on (could be selective: if only node mode) -------------("processors", "fonts", "builders.kernel.kerning") -- always on (could be selective: if only node mode) +appendaction("processors", "fonts", "builders.kernel.ligaturing") -- always on (could be selective: if only node mode) +appendaction("processors", "fonts", "builders.kernel.kerning") -- always on (could be selective: if only node mode) appendaction("processors", "fonts", "nodes.handlers.stripping") -- disabled (might move) ------------("processors", "fonts", "typesetters.italics.handler") -- disabled (after otf/kern handling) @@ -219,3 +220,18 @@ freezegroup("vboxbuilders", "normalizers") freezegroup("math", "normalizers") freezegroup("math", "builders") + +-- new: disabled here + +disableaction("processors", "builders.kernel.ligaturing") +disableaction("processors", "builders.kernel.kerning") + +directives.register("nodes.basepass", function(v) + if v then + disableaction("processors", "builders.kernel.ligaturing") + disableaction("processors", "builders.kernel.kerning") + else + enableaction("processors", "builders.kernel.ligaturing") + enableaction("processors", "builders.kernel.kerning") + end +end) diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua index 4b424e5a4..fdc7740de 100644 --- a/tex/context/base/typo-cap.lua +++ b/tex/context/base/typo-cap.lua @@ -33,6 +33,9 @@ local getchar = nuts.getchar local copy_node = nuts.copy local end_of_math = nuts.end_of_math +local traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id +local insert_after = nuts.insert_after local nodecodes = nodes.nodecodes local skipcodes = nodes.skipcodes @@ -72,6 +75,8 @@ local a_cases = attributes.private("case") local extract = bit32.extract local run = 0 -- a trick to make neighbouring ranges work +local blocked = { } + local function set(tag,font) if run == 2^6 then run = 1 @@ -104,88 +109,40 @@ end -- -- \WORD {far too \Word{many \WORD{more \word{pushed} in between} useless} words} -local uccodes = characters.uccodes -local lccodes = characters.lccodes +local uccodes = characters.uccodes +local lccodes = characters.lccodes +local categories = characters.categories -- true false true == mixed -local function helper(start,attr,lastfont,n,codes,special,once,keepother) +local function replacer(start,codes) local char = getchar(start) local dc = codes[char] if dc then local fnt = getfont(start) - if keepother and dc == char then - local lfa = lastfont[n] - if lfa then - setfield(start,"font",lfa) - return start, true - else - return start, false - end - else - if special then - local lfa = lastfont[n] - if lfa then - local previd = getid(getprev(start)) - if previd ~= glyph_code and previd ~= disc_code then - fnt = lfa - setfield(start,"font",lfa) - end + local ifc = fontchar[fnt] + if type(dc) == "table" then + for i=1,#dc do + if not ifc[dc[i]] then + return start, false end end - local ifc = fontchar[fnt] - if type(dc) == "table" then - local ok = true - for i=1,#dc do - -- could be cached in font - if not ifc[dc[i]] then - ok = false - break - end + for i=#dc,1,-1 do + local chr = dc[i] + if i == 1 then + setfield(start,"char",chr) + else + local g = copy_node(start) + setfield(g,"char",chr) + insert_after(start,start,g) end - if ok then - -- todo: use generic injector - local prev = start - local original = start - for i=1,#dc do - local chr = dc[i] - prev = start - if i == 1 then - setfield(start,"char",chr) - else - local g = copy_node(original) - setfield(g,"char",chr) - local next = getnext(start) - setfield(g,"prev",start) - if next then - setfield(g,"next",next) - setfield(start,"next",g) - setfield(next,"prev",g) - end - start = g - end - end - if once then - lastfont[n] = false - end - return prev, true - end - if once then - lastfont[n] = false - end - return start, false - elseif ifc[dc] then - setfield(start,"char",dc) - if once then - lastfont[n] = false - end - return start, true end + return start, true + elseif ifc[dc] then + setfield(start,"char",dc) + return start, true end end - if once then - lastfont[n] = false - end return start, false end @@ -206,147 +163,147 @@ end cases.register = register -local function WORD(start,attr,lastfont,n) +local function WORD(start,attr,lastfont,n,count,where,first) lastfont[n] = false - return helper(start,attr,lastfont,n,uccodes) + return replacer(first or start,uccodes) end -local function word(start,attr,lastfont,n) +local function word(start,attr,lastfont,n,count,where,first) lastfont[n] = false - return helper(start,attr,lastfont,n,lccodes) -end - -local function blockrest(start) - local n = getnext(start) - while n do - local id = getid(n) - if id == glyph_code or id == disc_node and getattr(n,a_cases) == attr then - setattr(n,a_cases,unsetvalue) - else - -- break -- we can have nested mess - end - n = getnext(n) - end + return replacer(first or start,lccodes) end -local function Word(start,attr,lastfont,n) -- looks quite complex - lastfont[n] = false - local prev = getprev(start) - if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then - prev = getprev(prev) - end - if not prev then - blockrest(start) - return helper(start,attr,lastfont,n,uccodes) +local function Words(start,attr,lastfont,n,count,where,first) -- looks quite complex + if where == "post" then + return end - local previd = getid(prev) - if previd ~= glyph_code and previd ~= disc_code then - -- only the first character is treated - blockrest(start) - -- we could return the last in the range and save some scanning - -- but why bother - return helper(start,attr,lastfont,n,uccodes) + if count == 1 and where ~= "post" then + replacer(first or start,uccodes) + return start, true, true else - return start, false + return start, false, true end end -local function Words(start,attr,lastfont,n) - lastfont[n] = false - local prev = getprev(start) - if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then - prev = getprev(prev) - end - if not prev then - return helper(start,attr,lastfont,n,uccodes) +local function Word(start,attr,lastfont,n,count,where,first) + blocked[attr] = true + return Words(start,attr,lastfont,n,count,where,first) +end + +local function camel(start,attr,lastfont,n,count,where,first) + local _, done_1 = word(start,attr,lastfont,n,count,where,first) + local _, done_2 = Words(start,attr,lastfont,n,count,where,first) + return start, done_1 or done_2, true +end + +local function mixed(start,attr,lastfont,n,count,where,first) + if where == "post" then + return end - local previd = getid(prev) - if previd ~= glyph_code and previd ~= disc_code then - return helper(start,attr,lastfont,n,uccodes) + local used = first or start + local char = getchar(first) + local dc = uccodes[char] + if not dc then + return start, false, true + elseif dc == char then + local lfa = lastfont[n] + if lfa then + setfield(first,"font",lfa) + return start, true, true + else + return start, false, true + end else - return start, false + replacer(first or start,uccodes) + return start, true, true end end -local function capital(start,attr,lastfont,n) -- 3 - return helper(start,attr,lastfont,n,uccodes,true,true) -end - -local function Capital(start,attr,lastfont,n) -- 4 - return helper(start,attr,lastfont,n,uccodes,true,false) +local function Capital(start,attr,lastfont,n,count,where,first,once) -- 3 + local used = first or start + if count == 1 and where ~= "post" then + local lfa = lastfont[n] + if lfa then + local dc = uccodes[getchar(used)] + if dc then + setfield(used,"font",lfa) + end + end + end + local s, d, c = replacer(first or start,uccodes) + if once then + lastfont[n] = false -- here + end + return start, d, c end -local function mixed(start,attr,lastfont,n) - return helper(start,attr,lastfont,n,uccodes,false,false,true) +local function capital(start,attr,lastfont,n,where,count,first,count) -- 4 + return Capital(start,attr,lastfont,n,where,count,first,true) end -local function none(start,attr,lastfont,n) - return start, false +local function none(start,attr,lastfont,n,count,where,first) + return start, false, true end -local function random(start,attr,lastfont,n) +local function random(start,attr,lastfont,n,count,where,first) + local used = first or start + local char = getchar(used) + local font = getfont(used) + local tfm = fontchar[font] lastfont[n] = false - local ch = getchar(start) - local tfm = fontchar[getfont(start)] - if lccodes[ch] then + local kind = categories[char] + if kind == "lu" then while true do - local d = chardata[randomnumber(1,0xFFFF)] - if d then - local uc = uccodes[d] - if uc and tfm[uc] then -- this also intercepts tables - setfield(start,"char",uc) - return start, true - end + local n = randomnumber(0x41,0x5A) + if tfm[n] then -- this also intercepts tables + setfield(used,"char",n) + return start, true end end - elseif uccodes[ch] then + elseif kind == "ll" then while true do - local d = chardata[randomnumber(1,0xFFFF)] - if d then - local lc = lccodes[d] - if lc and tfm[lc] then -- this also intercepts tables - setfield(start,"char",lc) - return start, true - end + local n = randomnumber(0x61,0x7A) + if tfm[n] then -- this also intercepts tables + setfield(used,"char",n) + return start, true end end end return start, false end -local function camel(start,attr,lastfont,n) - local start, done_1 = word(start,attr,lastfont,n) - local start, done_2 = Words(start,attr,lastfont,n) - return start, done_1 or done_2 -end - -register(variables.WORD, WORD) -- 1 -register(variables.word, word) -- 2 -register(variables.Word, Word) -- 3 -register(variables.Words, Words) -- 4 -register(variables.capital, capital) -- 5 -register(variables.Capital, Capital) -- 6 -register(variables.none, none) -- 7 (dummy) -register(variables.random, random) -- 8 -register(variables.mixed, mixed) -- 9 -register(variables.camel, camel) -- 10 +register(variables.WORD, WORD) -- 1 +register(variables.word, word) -- 2 +register(variables.Word, Word) -- 3 +register(variables.Words, Words) -- 4 +register(variables.capital,capital) -- 5 +register(variables.Capital,Capital) -- 6 +register(variables.none, none) -- 7 (dummy) +register(variables.random, random) -- 8 +register(variables.mixed, mixed) -- 9 +register(variables.camel, camel) -- 10 -register(variables.cap, variables.capital) -- clone -register(variables.Cap, variables.Capital) -- clone +register(variables.cap, variables.capital) -- clone +register(variables.Cap, variables.Capital) -- clone function cases.handler(head) -- not real fast but also not used on much data - head = tonut(head) local lastfont = { } local lastattr = nil local done = false - local start = head + local start = tonut(head) + local count = 0 + local previd = nil + local prev = nil while start do -- while because start can jump ahead local id = getid(start) if id == glyph_code then local attr = getattr(start,a_cases) - if attr and attr > 0 then + if attr and attr > 0 and not blocked[attr] then if attr ~= lastattr then lastattr = attr + count = 1 + else + count = count + 1 end setattr(start,a_cases,unsetvalue) local n, id, m = get(attr) @@ -355,7 +312,7 @@ function cases.handler(head) -- not real fast but also not used on much data end local action = actions[n] -- map back to low number if action then - start, ok = action(start,attr,lastfont,n) + start, ok = action(start,attr,lastfont,n,count) if ok then done = true end @@ -368,9 +325,10 @@ function cases.handler(head) -- not real fast but also not used on much data end elseif id == disc_code then local attr = getattr(start,a_cases) - if attr and attr > 0 then + if attr and attr > 0 and not blocked[attr] then if attr ~= lastattr then lastattr = attr + count = 0 end setattr(start,a_cases,unsetvalue) local n, id, m = get(attr) @@ -381,28 +339,73 @@ function cases.handler(head) -- not real fast but also not used on much data if action then local replace = getfield(start,"replace") if replace then - action(replace,attr,lastfont,n) + local cnt = count + for g in traverse_id(glyph_code,replace) do + cnt = cnt + 1 + -- setattr(g,a_cases,unsetvalue) + local _, _, quit = action(start,attr,lastfont,n,cnt,"replace",g) + if quit then break end + end end local pre = getfield(start,"pre") if pre then - action(pre,attr,lastfont,n) + local cnt = count + for g in traverse_id(glyph_code,pre) do + cnt = cnt + 1 + -- setattr(g,a_cases,unsetvalue) + local _, _, quit = action(start,attr,lastfont,n,cnt,"pre",g) + if quit then break end + end end local post = getfield(start,"post") if post then - action(post,attr,lastfont,n) + local cnt = count + for g in traverse_id(glyph_code,post) do + cnt = cnt + 1 + -- setattr(g,a_cases,unsetvalue) + local _, _, quit = action(start,attr,lastfont,n,cnt,"post",g) + if quit then break end + end end end + count = count + 1 end elseif id == math_code then start = end_of_math(start) + count = 0 + elseif prev_id == kern_code and getsubtype(prev) == kerning_code then + -- still inside a word ...nomally kerns are added later + else + count = 0 end - if start then -- why test - start = getnext(start) + if start then + prev = start + previd = id + start = getnext(start) end end - return tonode(head), done + return head, done end +-- function cases.handler(head) -- let's assume head doesn't change ... no reason +-- local done = false +-- local lastfont = { } +-- for first, last, size, attr in nuts.words(tonut(head),a_cases) do +-- local n, id, m = get(attr) +-- if lastfont[n] == nil then +-- lastfont[n] = id +-- end +-- local action = actions[n] +-- if action then +-- local _, ok = action(first,attr,lastfont,n) +-- if ok then +-- done = true +-- end +-- end +-- end +-- return head, done +-- end + local enabled = false function cases.set(n,id) diff --git a/tex/context/base/typo-cap.mkiv b/tex/context/base/typo-cap.mkiv index 9394cd7d0..eef4951fb 100644 --- a/tex/context/base/typo-cap.mkiv +++ b/tex/context/base/typo-cap.mkiv @@ -166,17 +166,20 @@ % % here we keep the \groupedcommand +% \def\typo_capitals_set_fake#1% +% {\edef\currentcapitals{#1}% +% \scratchcounter\fontid\font +% \usecapitalsstyleparameter\c!style +% \ctxcommand{setcharactercasing("\currentcapitals",\number\scratchcounter,\number\fontid\font)}} + \def\typo_capitals_set_fake#1% {\edef\currentcapitals{#1}% - %\setcharactercasing[\currentcapitals]% \ctxcommand{setcharactercasing("\currentcapitals",\number\fontid\font)}% - \signalcharacter % retain current style \usecapitalsstyleparameter\c!style} \def\typo_capitals_set_real#1% {\edef\currentcapitals{#1}% \sc - %\setcharactercasing[\currentcapitals]} \ctxcommand{setcharactercasing("\currentcapitals",\number\fontid\font)}} \unexpanded\def\pseudosmallcapped{\groupedcommand{\typo_capitals_set_fake\v!WORD }\donothing} % all upper diff --git a/tex/context/base/typo-itc.lua b/tex/context/base/typo-itc.lua index 7373c0321..60352120e 100644 --- a/tex/context/base/typo-itc.lua +++ b/tex/context/base/typo-itc.lua @@ -42,6 +42,7 @@ local setattr = nuts.setattr local insert_node_after = nuts.insert_after local delete_node = nuts.delete local end_of_math = nuts.end_of_math +local find_tail = nuts.tail local texgetattribute = tex.getattribute local texsetattribute = tex.setattribute @@ -98,16 +99,55 @@ end -- todo: clear attribute +local function okay(data,current,font,prevchar,previtalic,char,what) + if not data then + if trace_italics then + report_italics("ignoring %p between %s italic %C and italic %C",previtalic,what,prevchar,char) + end + return false + end + if threshold then + local ht = getfield(current,"height") + local ex = exheights[font] + local th = threshold * ex + if ht <= th then + if trace_italics then + report_italics("ignoring correction between %s italic %C and regular %C, height %p less than threshold %p",prevchar,what,char,ht,th) + end + return false + end + end + if trace_italics then + report_italics("inserting %p between %s italic %C and regular %C",previtalic,what,prevchar,char) + end + return true +end + function italics.handler(head) - head = tonut(head) - local done = false - local italic = 0 - local lastfont = nil - local lastattr = nil - local previous = nil - local prevchar = nil - local current = head - local inserted = nil + + local prev = nil + local prevchar = nil + local prevhead = tonut(head) + local previtalic = 0 + local previnserted = nil + + local replace = nil + local replacechar = nil + local replacehead = nil + local replaceitalic = 0 + local replaceinserted = nil + + local post = nil + local postchar = nil + local posthead = nil + local postitalic = 0 + local postinserted = nil + + local current = prevhead + local done = false + local lastfont = nil + local lastattr = nil + while current do local id = getid(current) if id == glyph_code then @@ -115,40 +155,45 @@ function italics.handler(head) local char = getchar(current) local data = italicsdata[font] if font ~= lastfont then - if italic ~= 0 then - if data then - if trace_italics then - report_italics("ignoring %p between italic %C and italic %C",italic,prevchar,char) + if previtalic ~= 0 then + if okay(data,current,font,prevchar,previtalic,char,"glyph") then + insert_node_after(prevhead,prev,new_correction_kern(previtalic)) + done = true + end + elseif previnserted and data then + if trace_italics then + report_italics("deleting last correction before %s %C",char,"glyph") + end + delete_node(prevhead,previnserted) + else + -- + if replaceitalic ~= 0 then + if okay(data,replace,font,replacechar,replaceitalic,char,"replace") then + insert_node_after(replacehead,replace,new_correction_kern(replaceitalic)) + done = true end - else - local okay = true - if threshold then - local ht = getfield(current,"height") - local ex = exheights[font] - local th = threshold * ex - if ht <= th then - if trace_italics then - report_italics("ignoring correction between italic %C and regular %C, height %p less than threshold %p",prevchar,char,ht,th) - end - okay = false - end + replaceitalic = 0 + elseif replaceinserted and data then + if trace_italics then + report_italics("deleting last correction before %s %C","replace",char) end - if okay then - if trace_italics then - report_italics("inserting %p between italic %C and regular %C",italic,prevchar,char) - end - insert_node_after(head,previous,new_correction_kern(italic)) + delete_node(replacehead,replaceinserted) + end + -- + if postitalic ~= 0 then + if okay(data,post,font,postchar,postitalic,char,"post") then + insert_node_after(posthead,post,new_correction_kern(postitalic)) done = true end + postitalic = 0 + elseif postinserted and data then + if trace_italics then + report_italics("deleting last correction before %s %C","post",char) + end + delete_node(posthead,postinserted) end - elseif inserted and data then - if trace_italics then - report_italics("deleting last correction before %C",char) - end - delete_node(head,inserted) - else - -- nothing end + -- lastfont = font end if data then @@ -157,63 +202,196 @@ function italics.handler(head) local cd = data[char] if not cd then -- this really can happen - italic = 0 + previtalic = 0 else - italic = cd.italic or cd.italic_correction - if not italic then - italic = setitalicinfont(font,char) -- calculated once - -- italic = 0 + previtalic = cd.italic or cd.italic_correction + if not previtalic then + previtalic = setitalicinfont(font,char) -- calculated once + -- previtalic = 0 end - if italic ~= 0 then + if previtalic ~= 0 then lastfont = font lastattr = attr - previous = current + prev = current + -- prevhead = head prevchar = char end end else - italic = 0 + previtalic = 0 end else - italic = 0 + previtalic = 0 end - inserted = nil + previnserted = nil + replaceinserted = nil + postinserted = nil elseif id == disc_code then - -- skip - elseif id == kern_code then - inserted = nil - italic = 0 + replace = getfield(current,"replace") + if replace then + local current = find_tail(replace) + local font = getfont(current) + local char = getchar(current) + local data = italicsdata[font] + if data then + local attr = forcedvariant or getattr(current,a_italics) + if attr and attr > 0 then + local cd = data[char] + if not cd then + -- this really can happen + replaceitalic = 0 + else + replaceitalic = cd.italic or cd.italic_correction + if not replaceitalic then + replaceitalic = setitalicinfont(font,char) -- calculated once + -- replaceitalic = 0 + end + if replaceitalic ~= 0 then + lastfont = font + lastattr = attr + replacechar = char + replacehead = replace + replace = current + end + end + else + replaceitalic = 0 + end + else + replaceitalic = 0 + end + replaceinserted = nil + end + local post = getfield(current,"post") + if post then + local current = find_tail(post) + local font = getfont(current) + local char = getchar(current) + local data = italicsdata[font] + if data then + local attr = forcedvariant or getattr(current,a_italics) + if attr and attr > 0 then + local cd = data[char] + if not cd then + -- this really can happen + postitalic = 0 + else + postitalic = cd.italic or cd.italic_correction + if not postitalic then + postitalic = setitalicinfont(font,char) -- calculated once + -- postitalic = 0 + end + if postitalic ~= 0 then + lastfont = font + lastattr = attr + postchar = char + posthead = post + post = current + end + end + else + postitalic = 0 + end + else + postitalic = 0 + end + postinserted = nil + end + elseif id == kern_code then -- how about fontkern ? + previnserted = nil + previtalic = 0 + replaceinserted = nil + replaceitalic = 0 + postinserted = nil + postitalic = 0 elseif id == glue_code then - if italic ~= 0 then + if previtalic ~= 0 then if trace_italics then - report_italics("inserting %p between italic %C and glue",italic,prevchar) + report_italics("inserting %p between %s italic %C and glue",previtalic,"glyph",prevchar) + end + previnserted = new_correction_glue(previtalic) -- maybe just add ? else problem with penalties + previtalic = 0 + done = true + insert_node_after(prevhead,prev,previnserted) + else + if replaceitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and glue",replaceitalic,"replace",replacechar) + end + replaceinserted = new_correction_kern(replaceitalic) -- needs to be a kern + replaceitalic = 0 + done = true + insert_node_after(replacehead,replace,replaceinserted) + end + if postitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and glue",postitalic,"post",postchar) + end + postinserted = new_correction_kern(postitalic) -- needs to be a kern + postitalic = 0 + done = true + insert_node_after(posthead,post,postinserted) end - inserted = new_correction_glue(italic) -- maybe just add ? else problem with penalties - insert_node_after(head,previous,inserted) - italic = 0 - done = true end elseif id == math_code then current = end_of_math(current) - elseif italic ~= 0 then - if trace_italics then - report_italics("inserting %p between italic %C and whatever",italic,prevchar) + else + if previtalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and whatever",previtalic,"glyph",prevchar) + end + insert_node_after(prevhead,prev,new_correction_kern(previtalic)) + previnserted = nil + previtalic = 0 + done = true + else + if replaceitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and whatever",replaceritalic,"replace",replacechar) + end + insert_node_after(replacehead,replace,new_correction_kern(replaceitalic)) + replaceitalic = 0 + replaceinserted = nil + done = true + end + if postitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and whatever",postitalic,"post",postchar) + end + insert_node_after(posthead,post,new_correction_kern(postitalic)) + postinserted = nil + postitalic = 0 + done = true + end end - inserted = nil - insert_node_after(head,previous,new_correction_kern(italic)) - italic = 0 - done = true end current = getnext(current) end - if italic ~= 0 and lastattr > 1 then -- more control is needed here - if trace_italics then - report_italics("inserting %p between italic %C and end of list",italic,prevchar) + if lastattr and lastattr > 1 then -- more control is needed here + if previtalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and end of list",previtalic,"glyph",prevchar) + end + insert_node_after(prevhead,prev,new_correction_kern(previtalic)) + done = true + else + if replaceitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and end of list",replaceitalic,"replace",replacechar) + end + insert_node_after(replacehead,replace,new_correction_kern(replaceitalic)) + done = true + end + if postitalic ~= 0 then + if trace_italics then + report_italics("inserting %p between %s italic %C and end of list",postitalic,"post",postchar) + end + insert_node_after(posthead,post,new_correction_kern(postitalic)) + done = true + end end - insert_node_after(head,previous,new_correction_kern(italic)) - done = true end - return tonode(head), done + return head, done end local enable diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua index a8ffe557b..5729c72c0 100644 --- a/tex/context/base/typo-krn.lua +++ b/tex/context/base/typo-krn.lua @@ -206,10 +206,12 @@ end -- needs checking ... base mode / node mode -- also use insert_before/after etc local function do_process(head,force) -- todo: glue so that we can fully stretch - local start, done, lastfont = head, false, nil + local start = head + local done = false + local lastfont = nil local keepligature = kerns.keepligature local keeptogether = kerns.keeptogether - local fillup = false + local fillup = false while start do -- faster to test for attr first local attr = force or getattr(start,a_kerns) @@ -217,7 +219,7 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch setattr(start,a_kerns,unsetvalue) local krn = mapping[attr] if krn == v_max then - krn = .25 + krn = .25 fillup = true else fillup = false @@ -233,8 +235,9 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch -- keep 'm else c = do_process(c,attr) - local s = start - local p, n = getprev(s), getnext(s) + local s = start + local p = getprev(s) + local n = getnext(s) local tail = find_node_tail(c) if p then setfield(p,"next",c) @@ -293,11 +296,14 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch -- 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 prv, nxt = getprev(disc), getnext(disc) + local prv = getprev(disc) + local nxt = getnext(disc) if getsubtype(disc) == discretionary_code then -- maybe we should forget about this variant as there is no glue - -- possible - local pre, post, replace = getfield(disc,"pre"), getfield(disc,"post"), getfield(disc,"replace") + -- possible .. hardly used so a copy doesn't hurt much + local pre = getfield(disc,"pre") + local post = getfield(disc,"post") + local replace = getfield(disc,"replace") if pre and prv then -- must pair with getprev(start) local before = copy_node(prv) setfield(pre,"prev",before) @@ -311,7 +317,7 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch end if post and nxt then -- must pair with start local after = copy_node(nxt) - local tail = find_node_tail(post) + local tail = find_node_tail(post) setfield(tail,"next",after) setfield(after,"prev",tail) setfield(after,"next",nil) @@ -322,8 +328,8 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch 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) + local after = copy_node(nxt) + local tail = find_node_tail(replace) setfield(replace,"prev",before) setfield(before,"next",replace) setfield(before,"prev",nil) @@ -338,9 +344,10 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch free_node(after) free_node(before) elseif prv and getid(prv) == glyph_code and getfont(prv) == lastfont then - local prevchar, lastchar = getchar(prv), getchar(start) - local kerns = chardata[lastfont][prevchar].kerns - local kern = kerns and kerns[lastchar] or 0 + local prevchar = getchar(prv) + local lastchar = getchar(start) + local kerns = chardata[lastfont][prevchar].kerns + local kern = kerns and kerns[lastchar] or 0 krn = kern + quaddata[lastfont]*krn -- here setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue else @@ -351,9 +358,10 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch -- this one happens in most cases: automatic (-), explicit (\-), regular (patterns) if prv and getid(prv) == glyph_code and getfont(prv) == lastfont then -- the normal case - local prevchar, lastchar = getchar(prv), getchar(start) - local kerns = chardata[lastfont][prevchar].kerns - local kern = kerns and kerns[lastchar] or 0 + local prevchar = getchar(prv) + local lastchar = getchar(start) + local kerns = chardata[lastfont][prevchar].kerns + local kern = kerns and kerns[lastchar] or 0 krn = kern + quaddata[lastfont]*krn else krn = quaddata[lastfont]*krn @@ -368,7 +376,9 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch local s = getfield(start,"spec") local w = getfield(s,"width") if w > 0 then - local width, stretch, shrink = w+gluefactor*w*krn, getfield(s,"stretch"), getfield(s,"shrink") + local width = w+gluefactor*w*krn + local stretch = getfield(s,"stretch") + local shrink = getfield(s,"shrink") setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w)) done = true end diff --git a/tex/generic/context/luatex/luatex-fonts-cbk.lua b/tex/generic/context/luatex/luatex-fonts-cbk.lua index 8632701d8..965b96893 100644 --- a/tex/generic/context/luatex/luatex-fonts-cbk.lua +++ b/tex/generic/context/luatex/luatex-fonts-cbk.lua @@ -18,21 +18,28 @@ local nodes = nodes local traverse_id = node.traverse_id local glyph_code = nodes.nodecodes.glyph +local disc_code = nodes.nodecodes.disc -- from now on we apply ligaturing and kerning here because it might interfere with complex -- opentype discretionary handling where the base ligature pass expect some weird extra -- pointers (which then confuse the tail slider that has some checking built in) -local ligaturing = node.ligaturing -local kerning = node.kerning +local ligaturing = node.ligaturing +local kerning = node.kerning -function node.ligaturing() texio.write_nl("warning: node.ligaturing is already applied") end -function node.kerning () texio.write_nl("warning: node.kerning is already applied") end +local basepass = true + +function nodes.handlers.setbasepass(v) + basepass = v +end function nodes.handlers.characters(head) local fontdata = fonts.hashes.identifiers if fontdata then - local usedfonts, basefonts, prevfont, basefont = { }, { }, nil, nil + local usedfonts = { } + local basefonts = { } + local prevfont = nil + local basefont = nil for n in traverse_id(glyph_code,head) do local font = n.font if font ~= prevfont then @@ -49,7 +56,7 @@ function nodes.handlers.characters(head) local processors = shared.processes if processors and #processors > 0 then usedfonts[font] = processors - else + elseif basepass then basefont = { n, nil } basefonts[#basefonts+1] = basefont end @@ -58,6 +65,30 @@ function nodes.handlers.characters(head) end end end + for d in traverse_id(disc_code,head) do + local r = d.replace + if r then + for n in traverse_id(glyph_code,r) do + local font = n.font + if font ~= prevfont then + prevfont = font + local used = usedfonts[font] + if not used then + local tfmdata = fontdata[font] -- + if tfmdata then + local shared = tfmdata.shared -- we need to check shared, only when same features + if shared then + local processors = shared.processes + if processors and #processors > 0 then + usedfonts[font] = processors + end + end + end + end + end + end + end + end if next(usedfonts) then for font, processors in next, usedfonts do for i=1,#processors do @@ -65,7 +96,7 @@ function nodes.handlers.characters(head) end end end - if #basefonts > 0 then + if basepass and #basefonts > 0 then for i=1,#basefonts do local range = basefonts[i] local start, stop = range[1], range[2] @@ -85,11 +116,13 @@ function nodes.handlers.characters(head) end function nodes.simple_font_handler(head) --- lang.hyphenate(head) + -- lang.hyphenate(head) head = nodes.handlers.characters(head) nodes.injections.handler(head) + if not basepass then + head = ligaturing(head) + head = kerning(head) + end nodes.handlers.protectglyphs(head) - -- head = node.ligaturing(head) - -- head = node.kerning(head) return head end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index e9c66382f..c000451c7 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 12/06/14 14:20:08 +-- merge date : 12/08/14 22:14:53 do -- begin closure to overcome local limits and interference @@ -14560,14 +14560,20 @@ local fonts=fonts local nodes=nodes local traverse_id=node.traverse_id local glyph_code=nodes.nodecodes.glyph +local disc_code=nodes.nodecodes.disc local ligaturing=node.ligaturing local kerning=node.kerning -function node.ligaturing() texio.write_nl("warning: node.ligaturing is already applied") end -function node.kerning () texio.write_nl("warning: node.kerning is already applied") end +local basepass=true +function nodes.handlers.setbasepass(v) + basepass=v +end function nodes.handlers.characters(head) local fontdata=fonts.hashes.identifiers if fontdata then - local usedfonts,basefonts,prevfont,basefont={},{},nil,nil + local usedfonts={} + local basefonts={} + local prevfont=nil + local basefont=nil for n in traverse_id(glyph_code,head) do local font=n.font if font~=prevfont then @@ -14584,7 +14590,7 @@ function nodes.handlers.characters(head) local processors=shared.processes if processors and #processors>0 then usedfonts[font]=processors - else + elseif basepass then basefont={ n,nil } basefonts[#basefonts+1]=basefont end @@ -14593,6 +14599,30 @@ function nodes.handlers.characters(head) end end end + for d in traverse_id(disc_code,head) do + local r=d.replace + if r then + for n in traverse_id(glyph_code,r) do + local font=n.font + if font~=prevfont then + prevfont=font + local used=usedfonts[font] + if not used then + local tfmdata=fontdata[font] + if tfmdata then + local shared=tfmdata.shared + if shared then + local processors=shared.processes + if processors and #processors>0 then + usedfonts[font]=processors + end + end + end + end + end + end + end + end if next(usedfonts) then for font,processors in next,usedfonts do for i=1,#processors do @@ -14600,7 +14630,7 @@ function nodes.handlers.characters(head) end end end - if #basefonts>0 then + if basepass and #basefonts>0 then for i=1,#basefonts do local range=basefonts[i] local start,stop=range[1],range[2] @@ -14621,6 +14651,10 @@ end function nodes.simple_font_handler(head) head=nodes.handlers.characters(head) nodes.injections.handler(head) + if not basepass then + head=ligaturing(head) + head=kerning(head) + end nodes.handlers.protectglyphs(head) return head end -- cgit v1.2.3