summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/typo-cap.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/typo-cap.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/typo-cap.lua203
1 files changed, 136 insertions, 67 deletions
diff --git a/Master/texmf-dist/tex/context/base/typo-cap.lua b/Master/texmf-dist/tex/context/base/typo-cap.lua
index 5f741da7c1d..2e20a95e7e4 100644
--- a/Master/texmf-dist/tex/context/base/typo-cap.lua
+++ b/Master/texmf-dist/tex/context/base/typo-cap.lua
@@ -8,36 +8,73 @@ if not modules then modules = { } end modules ['typo-cap'] = {
local next, type = next, type
local format, insert = string.format, table.insert
+local div = math.div
-local trace_casing = false trackers.register("nodes.casing", function(v) trace_casing = v end)
+local trace_casing = false trackers.register("typesetters.casing", function(v) trace_casing = v end)
-local has_attribute = node.has_attribute
-local unset_attribute = node.unset_attribute
-local set_attribute = node.set_attribute
-local traverse_id = node.traverse_id
+local report_casing = logs.reporter("typesetting","casing")
-local glyph = node.id("glyph")
-local kern = node.id("kern")
+local nodes, node = nodes, node
-local fontdata = fonts.ids
-local fontchar = fonts.chr
-local chardata = characters.data
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local traverse_id = node.traverse_id
+local copy_node = node.copy
-cases = cases or { }
-cases.actions = { }
-cases.attribute = attributes.private("case")
+local texattribute = tex.attribute
-local actions = cases.actions
-local lastfont = nil
+local nodecodes = nodes.nodecodes
+local skipcodes = nodes.skipcodes
+local kerncodes = nodes.kerncodes
--- we use char0 as placeholder for the larger font
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
-local function helper(start, code, codes, special, attribute, once)
+local kerning_code = kerncodes.kerning
+local userskip_code = skipcodes.userskip
+
+local tasks = nodes.tasks
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local fontchar = fonthashes.characters
+
+local chardata = characters.data
+
+typesetters = typesetters or { }
+local typesetters = typesetters
+
+typesetters.cases = typesetters.cases or { }
+local cases = typesetters.cases
+
+cases.actions = { }
+local actions = cases.actions
+cases.attribute = c_cases -- no longer needed
+local a_cases = attributes.private("case")
+
+local lastfont = nil
+
+-- 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:
+--
+-- \WORD {far too \Word{many \WORD{more \word{pushed} in between} useless} words}
+
+local uccodes = characters.uccodes
+local lccodes = characters.lccodes
+
+local function helper(start, codes, special, attribute, once)
local char = start.char
- local dc = chardata[char]
+ local dc = codes[char]
if dc then
local fnt = start.font
if special then
+ -- will become function
if start.char == 0 then
lastfont = fnt
local prev, next = start.prev, start.next
@@ -45,24 +82,24 @@ local function helper(start, code, codes, special, attribute, once)
if next then
next.prev = prev
end
+--~ node.free(start)
return prev, true
- elseif lastfont and start.prev.id ~= glyph then
+ elseif lastfont and start.prev.id ~= glyph_code then
fnt = lastfont
start.font = lastfont
end
end
- -- local ifc = fontdata[fnt].characters
local ifc = fontchar[fnt]
- local ucs = dc[codes]
- if ucs then
+ if type(dc) == "table" then
local ok = true
- for i=1,#ucs do
- ok = ok and ifc[ucs[i]]
+ for i=1,#dc do
+ ok = ok and ifc[dc[i]]
end
if ok then
+ -- tood; use generic injector
local prev, original = start, start
- for i=1,#ucs do
- local chr = ucs[i]
+ for i=1,#dc do
+ local chr = dc[i]
prev = start
if i == 1 then
start.char = chr
@@ -84,10 +121,8 @@ local function helper(start, code, codes, special, attribute, once)
end
if once then lastfont = nil end
return start, false
- end
- local uc = dc[code]
- if uc and ifc[uc] then
- start.char = uc
+ elseif ifc[dc] then
+ start.char = dc
if once then lastfont = nil end
return start, true
end
@@ -98,28 +133,32 @@ end
actions[1] = function(start,attribute)
lastfont = nil
- return helper(start,'uccode','uccodes')
+ return helper(start,uccodes)
end
actions[2] = function(start,attribute)
lastfont = nil
- return helper(start,'lccode','lccodes')
+ return helper(start,lccodes)
end
-actions[3] = function(start,attribute)
+actions[3] = function(start,attribute,attr)
lastfont = nil
local prev = start.prev
- if prev and prev.id == kern and prev.subtype == 0 then
+ if prev and prev.id == kern_code and prev.subtype == kerning_code then
prev = prev.prev
end
- if not prev or prev.id ~= glyph then
+ if not prev or prev.id ~= glyph_code then
--- only the first character is treated
- for n in traverse_id(glyph,start.next) do
- if has_attribute(n,attribute) then
+ for n in traverse_id(glyph_code,start.next) do
+ if has_attribute(n,attribute) == attr then
unset_attribute(n,attribute)
+ else
+ -- break -- we can have nested mess
end
end
- return helper(start,'uccode','uccodes')
+ -- we could return the last in the range and save some scanning
+ -- but why bother
+ return helper(start,uccodes)
else
return start, false
end
@@ -128,22 +167,22 @@ end
actions[4] = function(start,attribute)
lastfont = nil
local prev = start.prev
- if prev and prev.id == kern and prev.subtype == 0 then
+ if prev and prev.id == kern_code and prev.subtype == kerning_code then
prev = prev.prev
end
- if not prev or prev.id ~= glyph then
- return helper(start,'uccode','uccodes')
+ if not prev or prev.id ~= glyph_code then
+ return helper(start,uccodes)
else
return start, false
end
end
actions[5] = function(start,attribute) -- 3
- return helper(start,'uccode','uccodes',true,attribute,true)
+ return helper(start,uccodes,true,attribute,true)
end
actions[6] = function(start,attribute) -- 4
- return helper(start,'uccode','uccodes',true,attribute,false)
+ return helper(start,uccodes,true,attribute,false)
end
actions[8] = function(start)
@@ -152,59 +191,89 @@ actions[8] = function(start)
local mr = math.random
-- local tfm = fontdata[start.font].characters
local tfm = fontchar[start.font]
- if chardata[ch].lccode then
+ if lccodes[ch] then
while true do
local d = chardata[mr(1,0xFFFF)]
if d then
- local uc = d.uccode
- if uc and tfm[uc] then
+ local uc = uccodes[d]
+ if uc and tfm[uc] then -- this also intercepts tables
start.char = uc
return start, true
end
end
end
- elseif chardata[ch].uccode then
+ elseif uccodes[ch] then
while true do
local d = chardata[mr(1,0xFFFF)]
if d then
- local lc = d.lccode
- if lc and tfm[lc] then
+ local lc = lccodes[d]
+ if lc and tfm[lc] then -- this also intercepts tables
start.char = lc
return start, true
end
end
end
- else
- return start, false
end
+ return start, false
end
-- node.traverse_id_attr
-function cases.process(namespace,attribute,head) -- not real fast but also not used on much data
+local function process(namespace,attribute,head) -- not real fast but also not used on much data
lastfont = nil
+ local lastattr = nil
local done = false
- for start in traverse_id(glyph,head) do
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- unset_attribute(start,attribute)
- local action = actions[attr]
- if action then
- local _, ok = action(start,attribute)
- done = done and ok
+ local start = head
+ while start do -- while because start can jump ahead
+ local id = start.id
+ if id == glyph_code then
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ if attr ~= lastattr then
+ lastfont = nil
+ lastattr = attr
+ end
+ unset_attribute(start,attribute)
+ local action = actions[attr%100] -- map back to low number
+ if action then
+ start, ok = action(start,attribute,attr)
+ done = done and ok
+ if trace_casing then
+ report_casing("case trigger %s, instance %s, result %s",attr%100,div(attr,100),tostring(ok))
+ end
+ elseif trace_casing then
+ report_casing("unknown case trigger %s",attr)
+ end
end
end
+ if start then
+ start = start.next
+ end
end
lastfont = nil
return head, done
end
-chars.handle_casing = nodes.install_attribute_handler {
- name = "case",
- namespace = cases,
- processor = cases.process,
-}
+local m, enabled = 0, false -- a trick to make neighbouring ranges work
-function cases.enable()
- tasks.enableaction("processors","chars.handle_casing")
+function cases.set(n)
+ if not enabled then
+ tasks.enableaction("processors","typesetters.cases.handler")
+ if trace_casing then
+ report_casing("enabling case handler")
+ end
+ enabled = true
+ end
+ if m == 100 then
+ m = 1
+ else
+ m = m + 1
+ end
+ texattribute[a_cases] = m * 100 + n
end
+
+cases.handler = nodes.installattributehandler {
+ name = "case",
+ namespace = cases,
+ processor = process,
+}