summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/typo-drp.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
commit8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch)
tree94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mkiv/typo-drp.lua
parentf5aed2e51223c36c84c5f25a6cad238b2af59087 (diff)
downloadcontext-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mkiv/typo-drp.lua')
-rw-r--r--tex/context/base/mkiv/typo-drp.lua382
1 files changed, 382 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/typo-drp.lua b/tex/context/base/mkiv/typo-drp.lua
new file mode 100644
index 000000000..9d6d645d0
--- /dev/null
+++ b/tex/context/base/mkiv/typo-drp.lua
@@ -0,0 +1,382 @@
+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 getattr = nuts.getattr
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+local setlink = nuts.setlink
+local setprev = nuts.setprev
+local setnext = nuts.setnext
+local setchar = nuts.setchar
+
+local hpack_nodes = nuts.hpack
+
+local nodecodes = nodes.nodecodes
+
+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 localpar_code = nodecodes.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
+
+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
+-- 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
+ local id = getid(head)
+ if id == 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
+-- apply font
+
+-- local g = nodes.copy(tonode(current))
+-- g.subtype = 0
+-- nodes.handlers.characters(g)
+-- nodes.handlers.protectglyphs(g)
+-- setchar(current,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).
+ local prev = getprev(first)
+ local next = getnext(last)
+ --
+ setprev(first)
+ setnext(last)
+ 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)
+ --
+ setlink(prev,dropper)
+ setlink(dropper,next)
+ --
+ 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