diff options
Diffstat (limited to 'tex/context/base/typo-cap.lua')
-rw-r--r-- | tex/context/base/typo-cap.lua | 329 |
1 files changed, 125 insertions, 204 deletions
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua index 2988d5474..fdbf2e353 100644 --- a/tex/context/base/typo-cap.lua +++ b/tex/context/base/typo-cap.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['typo-cap'] = { local next, type = next, type local format, insert = string.format, table.insert -local div, randomnumber = math.div, math.random +local div = math.div local trace_casing = false trackers.register("typesetters.casing", function(v) trace_casing = v end) @@ -16,9 +16,12 @@ local report_casing = logs.reporter("typesetting","casing") local nodes, node = nodes, node -local copy_node = nodes.copy -local end_of_math = nodes.end_of_math +local traverse_id = node.traverse_id +local copy_node = node.copy +local end_of_math = node.end_of_math +local texattribute = tex.attribute +local unsetvalue = attributes.unsetvalue local nodecodes = nodes.nodecodes local skipcodes = nodes.skipcodes @@ -26,7 +29,6 @@ local kerncodes = nodes.kerncodes local glyph_code = nodecodes.glyph local kern_code = nodecodes.kern -local disc_code = nodecodes.disc local math_code = nodecodes.math local kerning_code = kerncodes.kerning @@ -42,8 +44,6 @@ local variables = interfaces.variables local v_reset = variables.reset local chardata = characters.data -local texsetattribute = tex.setattribute -local unsetvalue = attributes.unsetvalue typesetters = typesetters or { } local typesetters = typesetters @@ -53,125 +53,83 @@ local cases = typesetters.cases cases.actions = { } local actions = cases.actions +cases.attribute = c_cases -- no longer needed local a_cases = attributes.private("case") -local extract = bit32.extract -local run = 0 -- a trick to make neighbouring ranges work +local lastfont = nil -local function set(tag,font) - if run == 2^6 then - run = 1 - else - run = run + 1 - end - return font * 0x10000 + tag * 0x100 + run -end - -local function get(a) - local font = extract(a,16,12) -- 4000 - local tag = extract(a, 8, 8) -- 250 - local run = extract(a, 0, 8) -- 50 - return tag, font, run -end - --- print(get(set( 1, 0))) --- print(get(set( 1, 99))) --- print(get(set( 2, 96))) --- print(get(set( 30, 922))) --- print(get(set(250,4000))) - --- a previous implementation used char(0) as placeholder for the larger font, so we needed --- to remove it before it can do further harm ... that was too tricky as we use char 0 for --- other cases too +-- we use char(0) as placeholder for the larger font, so we need to remove it +-- before it can do further harm -- --- we could do the whole glyph run here (till no more attributes match) but then we end up --- with more code .. maybe i will clean this up anyway as the lastfont hack is somewhat ugly --- ... on the other hand, we need to deal with cases like: +-- we could do the whole glyph run here (till no more attributes match) but +-- then we end up with more code .. maybe i will clean this up anyway as the +-- lastfont hack is somewhat ugly .. on the other hand, we need to deal with +-- cases like: -- -- \WORD {far too \Word{many \WORD{more \word{pushed} in between} useless} words} local uccodes = characters.uccodes local lccodes = characters.lccodes --- true false true == mixed - -local function helper(start,attr,lastfont,n,codes,special,once,keepother) +local function helper(start, codes, special, attribute, once) local char = start.char - local dc = codes[char] + local dc = codes[char] if dc then local fnt = start.font - if keepother and dc == char then - local lfa = lastfont[n] - if lfa then - start.font = lfa - return start, true - else - return start, false - end - else - if special then - local lfa = lastfont[n] - if lfa then - local previd = start.prev.id - if previd ~= glyph_code and previd ~= disc_code then - fnt = lfa - setfield(start,"font",lfa) - end + if special then + -- will become function + if start.char == 0 then + lastfont = fnt + local prev, next = start.prev, start.next + prev.next = next + if next then + next.prev = prev end + return prev, true + elseif lastfont and start.prev.id ~= glyph_code then + fnt = lastfont + start.font = lastfont + end + end + local ifc = fontchar[fnt] + if type(dc) == "table" then + local ok = true + for i=1,#dc do + ok = ok and ifc[dc[i]] end - local ifc = fontchar[fnt] - if type(dc) == "table" then - local ok = true + if ok then + -- tood; use generic injector + local prev, original = start, start for i=1,#dc do - -- could be cached in font - if not ifc[dc[i]] then - ok = false - break - end - 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 - start.char = chr - else - local g = copy_node(original) - g.char = chr - local next = start.next - g.prev = start - if next then - g.next = next - start.next = g - next.prev = g - end - start = g + local chr = dc[i] + prev = start + if i == 1 then + start.char = chr + else + local g = copy_node(original) + g.char = chr + local next = start.next + g.prev = start + if next then + g.next = next + start.next = g + next.prev = g end + start = g 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 - start.char = dc - if once then - lastfont[n] = false - end - return start, true + if once then lastfont = nil end + return prev, true end + if once then lastfont = nil end + return start, false + elseif ifc[dc] then + start.char = dc + if once then lastfont = nil end + return start, true end end - if once then - lastfont[n] = false - end + if once then lastfont = nil end return start, false end @@ -192,91 +150,73 @@ end cases.register = register -local function WORD(start,attr,lastfont,n) - lastfont[n] = false - return helper(start,attr,lastfont,n,uccodes) +local function WORD(start,attribute) + lastfont = nil + return helper(start,uccodes) end -local function word(start,attr,lastfont,n) - lastfont[n] = false - return helper(start,attr,lastfont,n,lccodes) +local function word(start,attribute) + lastfont = nil + return helper(start,lccodes) end -local function blockrest(start) - local n = start.next - while n do - local id = n.id - if id == glyph_code or id == disc_node and n[a_cases] == attr then - n[a_cases] = unsetvalue - else - -- break -- we can have nested mess - end - n = n.next - end -end - -local function Word(start,attr,lastfont,n) -- looks quite complex - lastfont[n] = false +local function Word(start,attribute,attr) + lastfont = nil local prev = start.prev if prev and prev.id == kern_code and prev.subtype == kerning_code then prev = prev.prev end - if not prev then - blockrest(start) - return helper(start,attr,lastfont,n,uccodes) - end - local previd = prev.id - if previd ~= glyph_code and previd ~= disc_code then - -- only the first character is treated - blockrest(start) + if not prev or prev.id ~= glyph_code then + --- only the first character is treated + for n in traverse_id(glyph_code,start.next) do + if n[attribute] == attr then + n[attribute] = unsetvalue + else + -- break -- we can have nested mess + end + end -- we could return the last in the range and save some scanning -- but why bother - return helper(start,attr,lastfont,n,uccodes) + return helper(start,uccodes) else return start, false end end -local function Words(start,attr,lastfont,n) - lastfont[n] = false +local function Words(start,attribute) + lastfont = nil local prev = start.prev if prev and prev.id == kern_code and prev.subtype == kerning_code then prev = prev.prev end - if not prev then - return helper(start,attr,lastfont,n,uccodes) - end - local previd = prev.id - if previd ~= glyph_code and previd ~= disc_code then - return helper(start,attr,lastfont,n,uccodes) + if not prev or prev.id ~= glyph_code then + return helper(start,uccodes) else return start, false end end -local function capital(start,attr,lastfont,n) -- 3 - return helper(start,attr,lastfont,n,uccodes,true,true) +local function capital(start,attribute) -- 3 + return helper(start,uccodes,true,attribute,true) end -local function Capital(start,attr,lastfont,n) -- 4 - return helper(start,attr,lastfont,n,uccodes,true,false) +local function Capital(start,attribute) -- 4 + return helper(start,uccodes,true,attribute,false) end -local function mixed(start,attr,lastfont,n) - return helper(start,attr,lastfont,n,uccodes,false,false,true) -end - -local function none(start,attr,lastfont,n) +local function none(start) return start, false end -local function random(start,attr,lastfont,n) - lastfont[n] = false - local ch = start.char +local function random(start) + lastfont = nil + local ch = start.char + local mr = math.random + -- local tfm = fontdata[start.font].characters local tfm = fontchar[start.font] if lccodes[ch] then while true do - local d = chardata[randomnumber(1,0xFFFF)] + local d = chardata[mr(1,0xFFFF)] if d then local uc = uccodes[d] if uc and tfm[uc] then -- this also intercepts tables @@ -287,7 +227,7 @@ local function random(start,attr,lastfont,n) end elseif uccodes[ch] then while true do - local d = chardata[randomnumber(1,0xFFFF)] + local d = chardata[mr(1,0xFFFF)] if d then local lc = lccodes[d] if lc and tfm[lc] then -- this also intercepts tables @@ -308,67 +248,36 @@ 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.cap, variables.capital) -- clone register(variables.Cap, variables.Capital) -- clone -function cases.handler(head) -- not real fast but also not used on much data - local lastfont = { } +-- node.traverse_id_attr + +local function process(namespace,attribute,head) -- not real fast but also not used on much data + lastfont = nil local lastattr = nil - local done = false - local start = head + local done = false + local start = head while start do -- while because start can jump ahead local id = start.id if id == glyph_code then - local attr = start[a_cases] + local attr = start[attribute] if attr and attr > 0 then if attr ~= lastattr then + lastfont = nil lastattr = attr end - start[a_cases] = unsetvalue - local n, id, m = get(attr) - if lastfont[n] == nil then - lastfont[n] = id - end - local action = actions[n] -- map back to low number + start[attribute] = unsetvalue + local action = actions[attr%100] -- map back to low number if action then - start, ok = action(start,attr,lastfont,n) - if ok then - done = true - end + start, ok = action(start,attribute,attr) + done = done and ok if trace_casing then - report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,ok) + report_casing("case trigger %a, instance %a, result %a",attr%100,div(attr,100),ok) end elseif trace_casing then - report_casing("unknown case trigger %a",n) - end - end - elseif id == disc_code then - local attr = start[a_cases] - if attr and attr > 0 then - if attr ~= lastattr then - lastattr = attr - end - start[a_cases] = unsetvalue - local n, id, m = get(attr) - if lastfont[n] == nil then - lastfont[n] = id - end - local action = actions[n] -- map back to low number - if action then - local replace = start.replace - if replace then - action(replace,attr,lastfont,n) - end - local pre = start.pre - if pre then - action(pre,attr,lastfont,n) - end - local post = start.post - if post then - action(post,attr,lastfont,n) - end + report_casing("unknown case trigger %a",attr) end end elseif id == math_code then @@ -378,12 +287,13 @@ function cases.handler(head) -- not real fast but also not used on much data start = start.next end end + lastfont = nil return head, done end -local enabled = false +local m, enabled = 0, false -- a trick to make neighbouring ranges work -function cases.set(n,id) +function cases.set(n) if n == v_reset then n = unsetvalue else @@ -396,15 +306,26 @@ function cases.set(n,id) end enabled = true end - n = set(n,id) + if m == 100 then + m = 1 + else + m = m + 1 + end + n = m * 100 + n else n = unsetvalue end end - texsetattribute(a_cases,n) + texattribute[a_cases] = n -- return n -- bonus end +cases.handler = nodes.installattributehandler { + name = "case", + namespace = cases, + processor = process, +} + -- interface commands.setcharactercasing = cases.set |