diff options
Diffstat (limited to 'tex/context/base/typo-drp.lua')
-rw-r--r-- | tex/context/base/typo-drp.lua | 405 |
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 |