summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-drp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-drp.lua')
-rw-r--r--tex/context/base/typo-drp.lua405
1 files changed, 336 insertions, 69 deletions
diff --git a/tex/context/base/typo-drp.lua b/tex/context/base/typo-drp.lua
index 903140dae..4bbf0b8e9 100644
--- a/tex/context/base/typo-drp.lua
+++ b/tex/context/base/typo-drp.lua
@@ -11,9 +11,7 @@ if not modules then modules = { } end modules ['typo-drp'] = {
local tonumber, type, next = tonumber, type, next
local ceil = math.ceil
-
-local utfbyte = utf.byte
-local utfchar = utf.char
+local settings_to_hash = utilities.parsers.settings_to_hash
local trace_initials = false trackers.register("typesetters.initials", function(v) trace_initials = v end)
local report_initials = logs.reporter("nodes","initials")
@@ -24,19 +22,41 @@ typesetters.initials = initials or { }
local nodes = nodes
local tasks = nodes.tasks
-local hpack_nodes = nodes.hpack
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local hpack_nodes = nuts.hpack
+
local nodecodes = nodes.nodecodes
local whatsitcodes = nodes.whatsitcodes
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_kern = nodepool.kern
-local insert_before = nodes.insert_before
-local insert_after = nodes.insert_after
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
+local remove_node = nuts.remove
+local traverse_id = nuts.traverse_id
+local traverse = nuts.traverse
+local free_node = nuts.free
local variables = interfaces.variables
local v_default = variables.default
local v_margin = variables.margin
+local v_auto = variables.auto
+local v_first = variables.first
+local v_last = variables.last
local texget = tex.get
local texsetattribute = tex.setattribute
@@ -44,7 +64,8 @@ local unsetvalue = attributes.unsetvalue
local glyph_code = nodecodes.glyph
local hlist_code = nodecodes.hlist
-local kern_node = nodecodes.kern
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
local whatsit_code = nodecodes.whatsit
local localpar_code = whatsitcodes.localpar
@@ -56,6 +77,8 @@ local a_color = attributes.private('color')
local a_transparency = attributes.private('transparency')
local a_colorspace = attributes.private('colormodel')
+local category = characters.category
+
local settings = nil
function initials.set(specification)
@@ -68,7 +91,27 @@ function initials.set(specification)
texsetattribute(a_initial,1)
end
-commands.setinitial = initials.set
+interfaces.implement {
+ name = "setinitial",
+ actions = initials.set,
+ arguments = {
+ {
+ { "location" },
+ { "enabled", "boolean" },
+ { "method" },
+ { "distance" ,"dimen" },
+ { "hoffset" ,"dimen" },
+ { "voffset" ,"dimen" },
+ { "font", "integer" },
+ { "dynamic", "integer" },
+ { "ca", "integer" },
+ { "ma", "integer" },
+ { "ta", "integer" },
+ { "n", "integer" },
+ { "m", "integer" },
+ }
+ }
+}
-- dropped caps experiment (will be done properly when luatex
-- stores the state in the local par node) .. btw, search still
@@ -84,74 +127,297 @@ commands.setinitial = initials.set
-- todo: prevent linebreak .. but normally a initial ends up at the top of
-- a page so this has a low priority
+-- actions[v_default] = function(head,setting)
+-- local done = false
+-- if getid(head) == whatsit_code and getsubtype(head) == localpar_code then
+-- -- begin of par
+-- local first = getnext(head)
+-- -- parbox .. needs to be set at 0
+-- if first and getid(first) == hlist_code then
+-- first = getnext(first)
+-- end
+-- -- we need to skip over kerns and glues (signals)
+-- while first and getid(first) ~= glyph_code do
+-- first = getnext(first)
+-- end
+-- if first and getid(first) == glyph_code then
+-- local char = getchar(first)
+-- local prev = getprev(first)
+-- local next = getnext(first)
+-- -- if getid(prev) == hlist_code then
+-- -- -- set the width to 0
+-- -- end
+-- if next and getid(next) == kern_code then
+-- setfield(next,"kern",0)
+-- end
+-- if setting.font then
+-- setfield(first,"font",setting.font)
+-- end
+-- if setting.dynamic > 0 then
+-- setattr(first,0,setting.dynamic)
+-- end
+-- -- can be a helper
+-- local ma = setting.ma or 0
+-- local ca = setting.ca
+-- local ta = setting.ta
+-- if ca and ca > 0 then
+-- setattr(first,a_colorspace,ma == 0 and 1 or ma)
+-- setattr(first,a_color,ca)
+-- end
+-- if ta and ta > 0 then
+-- setattr(first,a_transparency,ta)
+-- end
+-- --
+-- local width = getfield(first,"width")
+-- local height = getfield(first,"height")
+-- local depth = getfield(first,"depth")
+-- local distance = setting.distance or 0
+-- local voffset = setting.voffset or 0
+-- local hoffset = setting.hoffset or 0
+-- local parindent = tex.parindent
+-- local baseline = texget("baselineskip").width
+-- local lines = tonumber(setting.n) or 0
+-- --
+-- setfield(first,"xoffset",- width - hoffset - distance - parindent)
+-- setfield(first,"yoffset",- voffset) -- no longer - height here
+-- -- We pack so that successive handling cannot touch the dropped cap. Packaging
+-- -- in a hlist is also needed because we cannot locally adapt e.g. parindent (not
+-- -- yet stored in with localpar).
+-- setfield(first,"prev",nil)
+-- setfield(first,"next",nil)
+-- local h = hpack_nodes(first)
+-- setfield(h,"width",0)
+-- setfield(h,"height",0)
+-- setfield(h,"depth",0)
+-- setfield(prev,"next",h)
+-- setfield(next,"prev",h)
+-- setfield(h,"next",next)
+-- setfield(h,"prev",prev)
+-- first = h
+-- -- end of packaging
+-- if setting.location == v_margin then
+-- -- okay
+-- else
+-- if lines == 0 then -- safeguard, not too precise
+-- lines = ceil((height+voffset) / baseline)
+-- end
+-- -- We cannot set parshape yet ... when we can I'll add a slope
+-- -- option (positive and negative, in emwidth).
+-- local hangafter = - lines
+-- local hangindent = width + distance + parindent
+-- if trace_initials then
+-- report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)
+-- end
+-- tex.hangafter = hangafter
+-- tex.hangindent = hangindent
+-- if parindent ~= 0 then
+-- insert_after(first,first,new_kern(-parindent))
+-- end
+-- end
+-- done = true
+-- end
+-- end
+-- return head, done
+-- end
+
actions[v_default] = function(head,setting)
local done = false
- if head.id == whatsit_code and head.subtype == localpar_code then
+ if getid(head) == whatsit_code and getsubtype(head) == localpar_code then
-- begin of par
- local first = head.next
+ local first = getnext(head)
+ local indent = false
-- parbox .. needs to be set at 0
- if first and first.id == hlist_code then
- first = first.next
+ if first and getid(first) == hlist_code then
+ first = getnext(first)
+ indent = true
end
-- we need to skip over kerns and glues (signals)
- while first and first.id ~= glyph_code do
- first = first.next
+ while first and getid(first) ~= glyph_code do
+ first = getnext(first)
end
- if first and first.id == glyph_code then
- local char = first.char
- local prev = first.prev
- local next = first.next
- -- if prev.id == hlist_code then
- -- -- set the width to 0
- -- end
- if next and next.id == kern_node then
- next.kern = 0
- end
- if setting.font then
- first.font = setting.font
- end
- if setting.dynamic > 0 then
- first[0] = setting.dynamic
- end
- -- can be a helper
- local ma = setting.ma or 0
- local ca = setting.ca
- local ta = setting.ta
- if ca and ca > 0 then
- first[a_colorspace] = ma == 0 and 1 or ma
- first[a_color] = ca
- end
- if ta and ta > 0 then
- first[a_transparency] = ta
- end
- --
- local width = first.width
- local height = first.height
- local depth = first.depth
+ if first and getid(first) == glyph_code then
+ local ma = setting.ma or 0
+ local ca = setting.ca
+ local ta = setting.ta
+ local last = first
local distance = setting.distance or 0
local voffset = setting.voffset or 0
local hoffset = setting.hoffset or 0
local parindent = tex.parindent
local baseline = texget("baselineskip").width
local lines = tonumber(setting.n) or 0
+ local dynamic = setting.dynamic
+ local font = setting.font
+ local method = settings_to_hash(setting.method)
+ local length = tonumber(setting.m) or 1
--
- first.xoffset = - width - hoffset - distance - parindent
- first.yoffset = - voffset -- no longer - height here
+ -- 1 char | n chars | skip first quote | ignore punct | keep punct
+ --
+ if getattr(first,a_initial) then
+ for current in traverse(getnext(first)) do
+ if getattr(current,a_initial) then
+ last = current
+ else
+ break
+ end
+ end
+ elseif method[v_auto] then
+ local char = getchar(first)
+ local kind = category(char)
+ if kind == "po" or kind == "pi" then
+ if method[v_first] then
+ -- remove quote etc before initial
+ local next = getnext(first)
+ if not next then
+ -- don't start with a quote or so
+ return head, false
+ end
+ last = nil
+ for current in traverse_id(glyph_code,next) do
+ head, first = remove_node(head,first,true)
+ first = current
+ last = first
+ break
+ end
+ if not last then
+ -- no following glyph or so
+ return head, false
+ end
+ else
+ -- keep quote etc with initial
+ local next = getnext(first)
+ if not next then
+ -- don't start with a quote or so
+ return head, false
+ end
+ for current in traverse_id(glyph_code,next) do
+ last = current
+ break
+ end
+ if last == first then
+ return head, false
+ end
+ end
+ elseif kind == "pf" then
+ -- error: final quote
+ else
+ -- okay
+ end
+ -- maybe also: get all A. B. etc
+ local next = getnext(first)
+ if next then
+ for current in traverse_id(glyph_code,next) do
+ local char = getchar(current)
+ local kind = category(char)
+ if kind == "po" then
+ if method[v_last] then
+ -- remove period etc after initial
+ remove_node(head,current,true)
+ else
+ -- keep period etc with initial
+ last = current
+ end
+ end
+ break
+ end
+ end
+ else
+ for current in traverse_id(glyph_code,first) do
+ last = current
+ if length <= 1 then
+ break
+ else
+ length = length - 1
+ end
+ end
+ end
+ local current = first
+ while true do
+ local id = getid(current)
+ if id == kern_code then
+ setfield(current,"kern",0)
+ elseif id == glyph_code then
+ local next = getnext(current)
+ if font then
+ setfield(current,"font",font)
+ end
+ if dynamic > 0 then
+ setattr(current,0,dynamic)
+ end
+-- apply font
+
+-- local g = nodes.copy(tonode(current))
+-- g.subtype = 0
+-- nodes.handlers.characters(g)
+-- nodes.handlers.protectglyphs(g)
+-- setfield(current,"char",g.char)
+-- nodes.free(g)
+
+ -- can be a helper
+ if ca and ca > 0 then
+ setattr(current,a_colorspace,ma == 0 and 1 or ma)
+ setattr(current,a_color,ca)
+ end
+ if ta and ta > 0 then
+ setattr(current,a_transparency,ta)
+ end
+ --
+ end
+ if current == last then
+ break
+ else
+ current = getnext(current)
+ end
+ end
-- We pack so that successive handling cannot touch the dropped cap. Packaging
-- in a hlist is also needed because we cannot locally adapt e.g. parindent (not
-- yet stored in with localpar).
- first.prev = nil
- first.next = nil
- local h = hpack_nodes(first)
- h.width = 0
- h.height = 0
- h.depth = 0
- prev.next = h
- next.prev = h
- h.next = next
- h.prev = prev
-
- -- end of packaging
+ local prev = getprev(first)
+ local next = getnext(last)
+ --
+ setfield(first,"prev",nil)
+ setfield(last,"next",nil)
+ local dropper = hpack_nodes(first)
+ local width = getfield(dropper,"width")
+ local height = getfield(dropper,"height")
+ local depth = getfield(dropper,"depth")
+ setfield(dropper,"width",0)
+ setfield(dropper,"height",0)
+ setfield(dropper,"depth",0)
+ --
+ setfield(prev,"next",dropper)
+ if next then
+ setfield(next,"prev",dropper)
+ end
+ setfield(dropper,"next",next)
+ setfield(dropper,"prev",prev)
+ --
+ if next then
+ local current = next
+ while current do
+ local id = getid(current)
+ if id == glue_code or id == kern_code then
+ local next = getnext(current)
+ -- remove_node(current,current,true) -- created an invalid next link and dangling remains
+ remove_node(head,current,true)
+ current = next
+ else
+ break
+ end
+ end
+ end
+ --
+ local hoffset = width + hoffset + distance + (indent and parindent or 0)
+ for current in traverse_id(glyph_code,first) do
+ setfield(current,"xoffset",- hoffset )
+ setfield(current,"yoffset",- voffset) -- no longer - height here
+ if current == last then
+ break
+ end
+ end
+ --
+ first = dropper
+ --
if setting.location == v_margin then
-- okay
else
@@ -161,15 +427,15 @@ actions[v_default] = function(head,setting)
-- We cannot set parshape yet ... when we can I'll add a slope
-- option (positive and negative, in emwidth).
local hangafter = - lines
- local hangindent = width + distance + parindent
+ local hangindent = width + distance
if trace_initials then
report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)
end
tex.hangafter = hangafter
tex.hangindent = hangindent
- if parindent ~= 0 then
- insert_after(first,first,new_kern(-parindent))
- end
+ end
+ if indent then
+ insert_after(first,first,new_kern(-parindent))
end
done = true
end
@@ -178,16 +444,17 @@ actions[v_default] = function(head,setting)
end
function initials.handler(head)
+ head = tonut(head)
local start = head
local attr = nil
while start do
- attr = start[a_initial]
+ attr = getattr(start,a_initial)
if attr then
break
- elseif start.id == glyph then
+ elseif getid(start) == glyph then
break
else
- start = start.next
+ start = getnext(start)
end
end
if attr then
@@ -201,8 +468,8 @@ function initials.handler(head)
report_initials("processing initials, alternative %a",alternative)
end
local head, done = action(head,settings)
- return head, done
+ return tonode(head), done
end
end
- return head, false
+ return tonode(head), false
end