summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-cap.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-cap.lua')
-rw-r--r--tex/context/base/typo-cap.lua329
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