diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/typo-drp.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/typo-drp.lua | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/typo-drp.lua b/Master/texmf-dist/tex/context/base/typo-drp.lua new file mode 100644 index 00000000000..9151100b6f9 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/typo-drp.lua @@ -0,0 +1,446 @@ +if not modules then modules = { } end modules ['typo-drp'] = { + version = 1.001, + comment = "companion to typo-drp.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This ons is sensitive for order (e.g. when combined with first line +-- processing. + +local tonumber, type, next = tonumber, type, next +local ceil = math.ceil +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") + +local initials = typesetters.paragraphs or { } +typesetters.initials = initials or { } + +local nodes = nodes +local tasks = nodes.tasks + +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 = nuts.pool +local new_kern = nodepool.kern + +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 +local unsetvalue = attributes.unsetvalue + +local glyph_code = nodecodes.glyph +local hlist_code = nodecodes.hlist +local glue_code = nodecodes.glue +local kern_code = nodecodes.kern +local whatsit_code = nodecodes.whatsit +local localpar_code = whatsitcodes.localpar + +local actions = { } +initials.actions = actions + +local a_initial = attributes.private("initial") +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) + settings = specification or { } + settings.enabled = true + tasks.enableaction("processors","typesetters.initials.handler") + if trace_initials then + report_initials("enabling initials") + end + texsetattribute(a_initial,1) +end + +commands.setinitial = initials.set + +-- dropped caps experiment (will be done properly when luatex +-- stores the state in the local par node) .. btw, search still +-- works with dropped caps, as does an export + +-- we need a 'par' attribute and in fact for dropped caps we don't need +-- need an attribute ... dropit will become s state counter (or end up +-- in the localpar user data + +-- for the moment, each paragraph gets a number as id (attribute) ..problem +-- with nesting .. or anyhow, needed for tagging anyway + +-- 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 getid(head) == whatsit_code and getsubtype(head) == localpar_code then + -- begin of par + local first = getnext(head) + local indent = false + -- parbox .. needs to be set at 0 + 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 getid(first) ~= glyph_code do + first = getnext(first) + end + 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 + -- + -- 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 + -- 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). + 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 + 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 + if trace_initials then + report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent) + end + tex.hangafter = hangafter + tex.hangindent = hangindent + end + if indent then + insert_after(first,first,new_kern(-parindent)) + end + done = true + end + end + return head, done +end + +function initials.handler(head) + head = tonut(head) + local start = head + local attr = nil + while start do + attr = getattr(start,a_initial) + if attr then + break + elseif getid(start) == glyph then + break + else + start = getnext(start) + end + end + if attr then + -- here as we can process nested boxes first so we need to keep state + tasks.disableaction("processors","typesetters.initials.handler") + -- texsetattribute(attribute,unsetvalue) + local alternative = settings.alternative or v_default + local action = actions[alternative] or actions[v_default] + if action then + if trace_initials then + report_initials("processing initials, alternative %a",alternative) + end + local head, done = action(head,settings) + return tonode(head), done + end + end + return tonode(head), false +end |