summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2020-12-06 18:45:33 +0100
committerContext Git Mirror Bot <phg@phi-gamma.net>2020-12-06 18:45:33 +0100
commitaff2893a6d6652223e92e3de18e1260cbd533fea (patch)
tree0167244365922a9a3bddad5dfce4aafe7cc6ec8b /tex
parent0477f879e2b574ad568732ad03784e5df1952fb7 (diff)
downloadcontext-aff2893a6d6652223e92e3de18e1260cbd533fea.tar.gz
2020-12-06 18:14:00
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/mkii/cont-new.mkii2
-rw-r--r--tex/context/base/mkii/context.mkii2
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-rw-r--r--tex/context/base/mkiv/context.mkiv2
-rw-r--r--tex/context/base/mkiv/grph-rul.lua6
-rw-r--r--tex/context/base/mkiv/node-bck.lua3
-rw-r--r--tex/context/base/mkiv/node-syn.lua5
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin26096 -> 26086 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin255677 -> 255761 bytes
-rw-r--r--tex/context/base/mkiv/typo-spa.lua246
-rw-r--r--tex/context/base/mkxl/back-pdf.mkxl1
-rw-r--r--tex/context/base/mkxl/colo-nod.lmt40
-rw-r--r--tex/context/base/mkxl/colo-nod.mkxl20
-rw-r--r--tex/context/base/mkxl/cont-new.mkxl2
-rw-r--r--tex/context/base/mkxl/context.mkxl3
-rw-r--r--tex/context/base/mkxl/grph-rul.lmt124
-rw-r--r--tex/context/base/mkxl/grph-rul.mkxl2
-rw-r--r--tex/context/base/mkxl/lpdf-lmt.lmt57
-rw-r--r--tex/context/base/mkxl/lpdf-rul.lmt392
-rw-r--r--tex/context/base/mkxl/node-bck.lmt294
-rw-r--r--tex/context/base/mkxl/node-bck.mkxl2
-rw-r--r--tex/context/base/mkxl/node-ini.mkxl2
-rw-r--r--tex/context/base/mkxl/node-ref.lmt10
-rw-r--r--tex/context/base/mkxl/node-rul.lmt203
-rw-r--r--tex/context/base/mkxl/node-rul.mkxl5
-rw-r--r--tex/context/base/mkxl/node-tra.lmt734
-rw-r--r--tex/context/base/mkxl/typo-drp.lmt346
-rw-r--r--tex/context/base/mkxl/typo-drp.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-fln.lmt406
-rw-r--r--tex/context/base/mkxl/typo-fln.mkxl2
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua2
31 files changed, 2725 insertions, 192 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index 5039c26aa..d6a41419c 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2020.12.04 20:19}
+\newcontextversion{2020.12.06 18:12}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 8b103d931..d3ff08369 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2020.12.04 20:19}
+\edef\contextversion{2020.12.06 18:12}
%D For those who want to use this:
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index e77e90e59..b8b97f52b 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2020.12.04 20:19}
+\newcontextversion{2020.12.06 18:12}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index fd88f9914..dc6bc1a4c 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -45,7 +45,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2020.12.04 20:19}
+\edef\contextversion{2020.12.06 18:12}
%D Kind of special:
diff --git a/tex/context/base/mkiv/grph-rul.lua b/tex/context/base/mkiv/grph-rul.lua
index 5067b0165..0582a0ad0 100644
--- a/tex/context/base/mkiv/grph-rul.lua
+++ b/tex/context/base/mkiv/grph-rul.lua
@@ -87,6 +87,8 @@ do
local replacer = utilities.templates.replacer
+ -- todo: RuleColor -> just string ?
+
local predefined = {
["fake:word"] = replacer [[
FakeWord(%width%,%height%,%depth%,%line%,%color%);
@@ -133,7 +135,9 @@ def RuleColor = %color% enddef ;
initialized = true
simplemetapost("rulefun",formatters["randomseed := %s;"](getrandom("rulefun",0,4095)))
end
- local pdf = caching and cache[code] or simplemetapost("rulefun",code) -- w, h, d
+ -- we enable extensions but we could also consider to delegate colors
+ -- to the node finalizer
+ local pdf = caching and cache[code] or simplemetapost("rulefun",code,true)
if trace_mp then
report_mp("code: %s",code)
report_mp("pdf : %s",pdf)
diff --git a/tex/context/base/mkiv/node-bck.lua b/tex/context/base/mkiv/node-bck.lua
index 82c800de8..ec84a3db5 100644
--- a/tex/context/base/mkiv/node-bck.lua
+++ b/tex/context/base/mkiv/node-bck.lua
@@ -63,9 +63,6 @@ local unsetvalue = attributes.unsetvalue
local linefillers = nodes.linefillers
-local a_color = privateattributes("color")
-local a_transparency = privateattributes("transparency")
-local a_colormodel = privateattributes("colormodel")
local a_background = privateattributes("background")
local a_alignbackground = privateattributes("alignbackground")
local a_linefiller = privateattributes("linefiller")
diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua
index b3ce4a7e3..d9c653abb 100644
--- a/tex/context/base/mkiv/node-syn.lua
+++ b/tex/context/base/mkiv/node-syn.lua
@@ -849,11 +849,12 @@ implement {
actions = synctex.resume,
}
-interfaces.implement {
+implement {
name = "synctexpushline",
actions = synctex.pushline,
}
-interfaces.implement {
+
+implement {
name = "synctexpopline",
actions = synctex.popline,
}
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index 22286e42d..f61ff2582 100644
--- a/tex/context/base/mkiv/status-files.pdf
+++ b/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 844a0c16e..75f0d1787 100644
--- a/tex/context/base/mkiv/status-lua.pdf
+++ b/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/typo-spa.lua b/tex/context/base/mkiv/typo-spa.lua
new file mode 100644
index 000000000..78fc22964
--- /dev/null
+++ b/tex/context/base/mkiv/typo-spa.lua
@@ -0,0 +1,246 @@
+if not modules then modules = { } end modules ['typo-spa'] = {
+ version = 1.001,
+ comment = "companion to typo-spa.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+
+local trace_spacing = false trackers.register("typesetters.spacing", function(v) trace_spacing = v end)
+
+local report_spacing = logs.reporter("typesetting","spacing")
+
+local nodes, fonts, node = nodes, fonts, node
+
+local fonthashes = fonts.hashes
+local quaddata = fonthashes.quads
+
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
+
+local v_reset = interfaces.variables.reset
+
+local nuts = nodes.nuts
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local takeattr = nuts.takeattr
+local isglyph = nuts.isglyph
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local end_of_math = nuts.end_of_math
+
+local nodepool = nuts.pool
+local new_penalty = nodepool.penalty
+local new_glue = nodepool.glue
+
+local nodecodes = nodes.nodecodes
+local math_code = nodecodes.math
+
+local somespace = nodes.somespace
+local somepenalty = nodes.somepenalty
+
+local enableaction = nodes.tasks.enableaction
+
+typesetters = typesetters or { }
+local typesetters = typesetters
+
+typesetters.spacings = typesetters.spacings or { }
+local spacings = typesetters.spacings
+
+spacings.mapping = spacings.mapping or { }
+spacings.numbers = spacings.numbers or { }
+
+local a_spacings = attributes.private("spacing")
+
+storage.register("typesetters/spacings/mapping", spacings.mapping, "typesetters.spacings.mapping")
+
+local mapping = spacings.mapping
+local numbers = spacings.numbers
+
+for i=1,#mapping do
+ local m = mapping[i]
+ numbers[m.name] = m
+end
+
+-- todo cache lastattr
+
+function spacings.handler(head)
+ local start = head
+ -- head is always begin of par (whatsit), so we have at least two prev nodes
+ -- penalty followed by glue
+ while start do
+ local char, id = isglyph(start)
+ if char then
+ local attr = takeattr(start,a_spacings)
+ if attr and attr > 0 then
+ local data = mapping[attr]
+ if data then
+ local map = data.characters[char]
+ if map then
+ local font = id
+ local left = map.left
+ local right = map.right
+ local alternative = map.alternative
+ local quad = quaddata[font]
+ local prev = getprev(start)
+ if left and left ~= 0 and prev then
+ local ok = false
+ local prevprev = getprev(prev)
+ if alternative == 1 then
+ local somespace = somespace(prev,true)
+ if somespace then
+ local somepenalty = somepenalty(prevprev,10000)
+ if somepenalty then
+ if trace_spacing then
+ report_spacing("removing penalty and space before %C (left)",char)
+ end
+ head = remove_node(head,prev,true)
+ head = remove_node(head,prevprev,true)
+ else
+ if trace_spacing then
+ report_spacing("removing space before %C (left)",char)
+ end
+ head = remove_node(head,prev,true)
+ end
+ end
+ ok = true
+ else
+ ok = not (somespace(prev,true) and somepenalty(prevprev,true)) or somespace(prev,true)
+ end
+ if ok then
+ if trace_spacing then
+ report_spacing("inserting penalty and space before %C (left)",char)
+ end
+ insert_node_before(head,start,new_penalty(10000))
+ insert_node_before(head,start,new_glue(left*quad))
+ end
+ end
+ local next = getnext(start)
+ if right and right ~= 0 and next then
+ local ok = false
+ local nextnext = getnext(next)
+ if alternative == 1 then
+ local somepenalty = somepenalty(next,10000)
+ if somepenalty then
+ local somespace = somespace(nextnext,true)
+ if somespace then
+ if trace_spacing then
+ report_spacing("removing penalty and space after %C right",char)
+ end
+ head = remove_node(head,next,true)
+ head = remove_node(head,nextnext,true)
+ end
+ else
+ local somespace = somespace(next,true)
+ if somespace then
+ if trace_spacing then
+ report_spacing("removing space after %C (right)", char)
+ end
+ head = remove_node(head,next,true)
+ end
+ end
+ ok = true
+ else
+ ok = not (somepenalty(next,10000) and somespace(nextnext,true)) or somespace(next,true)
+ end
+ if ok then
+ if trace_spacing then
+ report_spacing("inserting penalty and space after %C (right)",char)
+ end
+ insert_node_after(head,start,new_glue(right*quad))
+ insert_node_after(head,start,new_penalty(10000))
+ end
+ end
+ end
+ end
+ end
+ elseif id == math_code then
+ start = end_of_math(start) -- weird, can return nil .. no math end?
+ end
+ if start then
+ start = getnext(start)
+ end
+ end
+ return head
+end
+
+local enabled = false
+
+function spacings.define(name)
+ local data = numbers[name]
+ if data then
+ -- error
+ else
+ local number = #mapping + 1
+ local data = {
+ name = name,
+ number = number,
+ characters = { },
+ }
+ mapping[number] = data
+ numbers[name] = data
+ end
+end
+
+function spacings.setup(name,char,settings)
+ local data = numbers[name]
+ if not data then
+ -- error
+ else
+ data.characters[char] = settings
+ end
+end
+
+function spacings.set(name)
+ local n = unsetvalue
+ if name ~= v_reset then
+ local data = numbers[name]
+ if data then
+ if not enabled then
+ enableaction("processors","typesetters.spacings.handler")
+ enabled = true
+ end
+ n = data.number or unsetvalue
+ end
+ end
+ texsetattribute(a_spacings,n)
+end
+
+function spacings.reset()
+ texsetattribute(a_spacings,unsetvalue)
+end
+
+-- interface
+
+local implement = interfaces.implement
+
+implement {
+ name = "definecharacterspacing",
+ actions = spacings.define,
+ arguments = "string"
+}
+
+implement {
+ name = "setupcharacterspacing",
+ actions = spacings.setup,
+ arguments = {
+ "string",
+ "integer",
+ {
+ { "left", "number" },
+ { "right", "number" },
+ { "alternative", "integer" },
+ }
+ }
+}
+
+implement {
+ name = "setcharacterspacing",
+ actions = spacings.set,
+ arguments = "string"
+}
diff --git a/tex/context/base/mkxl/back-pdf.mkxl b/tex/context/base/mkxl/back-pdf.mkxl
index 171c6e7b6..66db06ef1 100644
--- a/tex/context/base/mkxl/back-pdf.mkxl
+++ b/tex/context/base/mkxl/back-pdf.mkxl
@@ -39,6 +39,7 @@
\registerctxluafile{lpdf-epa}{autosuffix}
\registerctxluafile{lpdf-emb}{autosuffix,optimize}
\registerctxluafile{lpdf-fnt}{autosuffix}
+\registerctxluafile{lpdf-rul}{autosuffix}
\registerctxluafile{back-pdp}{autosuffix}
\registerctxluafile{back-pdf}{autosuffix} % some code will move to lpdf-*
diff --git a/tex/context/base/mkxl/colo-nod.lmt b/tex/context/base/mkxl/colo-nod.lmt
new file mode 100644
index 000000000..d65f5978c
--- /dev/null
+++ b/tex/context/base/mkxl/colo-nod.lmt
@@ -0,0 +1,40 @@
+if not modules then modules = { } end modules ['node-tra'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local nuts = nodes.nuts
+
+local setattrs = nuts.setattrs
+
+local privateattributes = attributes.private
+
+local a_color = privateattributes('color')
+local a_transparency = privateattributes('transparency')
+local a_colormodel = privateattributes('colormodel')
+
+local colors = { }
+nuts.colors = colors
+
+function colors.set(n,ma,ca,ta) -- we could also do layers here
+ if ca then
+ if ca > 0 then
+ if not ma or ma == 0 then
+ ma = 1
+ end
+ if ta then
+ setattrs(n,a_colorspace,ma,a_color,ca,a_transparency,ta)
+ else
+ setattrs(n,a_colorspace,ma,a_color,ca)
+ end
+ end
+ elseif ta then
+ if ta > 0 then
+ setattr(n,a_transparency,ta)
+ end
+ end
+ return n
+end
diff --git a/tex/context/base/mkxl/colo-nod.mkxl b/tex/context/base/mkxl/colo-nod.mkxl
new file mode 100644
index 000000000..3cc3db033
--- /dev/null
+++ b/tex/context/base/mkxl/colo-nod.mkxl
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=colo-nod,
+%D version=2020.12.03,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Nodes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Color Macros / Nodes}
+
+%D In \LMTX\ we moved some code here.
+
+\registerctxluafile{colo-nod}{}
+
+\endinput
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index f56aaae6a..3c11528a8 100644
--- a/tex/context/base/mkxl/cont-new.mkxl
+++ b/tex/context/base/mkxl/cont-new.mkxl
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2020.12.04 20:19}
+\newcontextversion{2020.12.06 18:12}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl
index 40fca9fd9..5eca52575 100644
--- a/tex/context/base/mkxl/context.mkxl
+++ b/tex/context/base/mkxl/context.mkxl
@@ -29,7 +29,7 @@
%D {YYYY.MM.DD HH:MM} format.
\immutable\edef\contextformat {\jobname}
-\immutable\edef\contextversion{2020.12.04 20:19}
+\immutable\edef\contextversion{2020.12.06 18:12}
%overloadmode 1 % check frozen / warning
%overloadmode 2 % check frozen / error
@@ -220,6 +220,7 @@
\loadmkxlfile{core-dat}
\loadmkxlfile{colo-ini}
+\loadmkxlfile{colo-nod}
\loadmkxlfile{colo-grp} % optional
\loadmkxlfile{colo-ext}
diff --git a/tex/context/base/mkxl/grph-rul.lmt b/tex/context/base/mkxl/grph-rul.lmt
new file mode 100644
index 000000000..d8da5f760
--- /dev/null
+++ b/tex/context/base/mkxl/grph-rul.lmt
@@ -0,0 +1,124 @@
+if not modules then modules = { } end modules ['grph-rul'] = {
+ version = 1.001,
+ comment = "companion to grph-rul.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local attributes = attributes
+local nodes = nodes
+local context = context
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+local userrule = nuts.rules.userrule
+local outlinerule = nuts.pool.outlinerule
+local ruleactions = nuts.rules.ruleactions
+
+local setattrlist = nuts.setattrlist
+local setattr = nuts.setattr
+local tonode = nuts.tonode
+
+local getattribute = tex.getattribute
+
+local a_color = attributes.private('color')
+local a_transparency = attributes.private('transparency')
+local a_colormodel = attributes.private('colormodel')
+
+local floor = math.floor
+local getrandom = utilities.randomizer.get
+
+do
+
+ local function unsupported() end
+
+ ruleactions.mp = unsupported
+ ruleactions.fill = unsupported
+ ruleactions.draw = unsupported
+ ruleactions.stroke = unsupported
+ ruleactions.box = unsupported
+
+end
+
+interfaces.implement {
+ name = "frule",
+ arguments = { {
+ { "width", "dimension" },
+ { "height", "dimension" },
+ { "depth", "dimension" },
+ { "radius", "dimension" },
+ { "line", "dimension" },
+ { "type", "string" },
+ { "data", "string" },
+ { "name", "string" },
+ { "radius", "dimension" },
+ { "corner", "string" },
+ } } ,
+ actions = function(t)
+ local rule = userrule(t)
+ if t.type == "mp" then
+ t.ma = getattribute(a_colormodel) or 1
+ t.ca = getattribute(a_color)
+ t.ta = getattribute(a_transparency)
+ else
+ setattrlist(rule,true)
+ end
+ context(tonode(rule)) -- will become context.nodes.flush
+ end
+}
+
+interfaces.implement {
+ name = "outlinerule",
+ public = true,
+ protected = true,
+ arguments = { {
+ { "width", "dimension" },
+ { "height", "dimension" },
+ { "depth", "dimension" },
+ { "line", "dimension" },
+ } } ,
+ actions = function(t)
+ local rule = outlinerule(t.width,t.height,t.depth,t.line)
+ setattrlist(rule,true)
+ context(tonode(rule)) -- will become context.nodes.flush
+ end
+}
+
+interfaces.implement {
+ name = "framedoutline",
+ arguments = { "dimension", "dimension", "dimension", "dimension" },
+ actions = function(w,h,d,l)
+ local rule = outlinerule(w,h,d,l)
+ setattrlist(rule,true)
+ context(tonode(rule)) -- will become context.nodes.flush
+ end
+}
+
+interfaces.implement {
+ name = "fakeword",
+ arguments = { {
+ { "factor", "dimension" },
+ { "name", "string" }, -- can be type
+ { "min", "dimension" },
+ { "max", "dimension" },
+ { "n", "integer" },
+ } } ,
+ actions = function(t)
+ local factor = t.factor or 0
+ local amount = getrandom("fakeword",t.min,t.max)
+ local rule = userrule {
+ height = 1.25*factor,
+ depth = 0.25*factor,
+ width = floor(amount/10000) * 10000,
+ line = 0.10*factor,
+ ma = getattribute(a_colormodel) or 1,
+ ca = getattribute(a_color),
+ ta = getattribute(a_transparency),
+ type = "mp",
+ name = t.name,
+ }
+ setattrlist(rule,true)
+ context(tonode(rule))
+ end
+}
diff --git a/tex/context/base/mkxl/grph-rul.mkxl b/tex/context/base/mkxl/grph-rul.mkxl
index ef65b1fe4..034e91734 100644
--- a/tex/context/base/mkxl/grph-rul.mkxl
+++ b/tex/context/base/mkxl/grph-rul.mkxl
@@ -13,7 +13,7 @@
\writestatus{loading}{ConTeXt Graphic Macros / Rule Trickery}
-\registerctxluafile{grph-rul}{}
+\registerctxluafile{grph-rul}{autosuffix}
\unprotect
diff --git a/tex/context/base/mkxl/lpdf-lmt.lmt b/tex/context/base/mkxl/lpdf-lmt.lmt
index cbad20f09..d1c5e59f7 100644
--- a/tex/context/base/mkxl/lpdf-lmt.lmt
+++ b/tex/context/base/mkxl/lpdf-lmt.lmt
@@ -815,6 +815,7 @@ local flushsave, flushrestore, flushsetmatrix do
local m = p.matrix
if m then
local rx, sx, sy, ry = unpack(m)
+ local s
if not rx then
rx = 1
elseif rx == 0 then
@@ -832,6 +833,16 @@ local flushsave, flushrestore, flushsetmatrix do
sy = 0
end
--
+ if sx == 0 and sy == 0 then
+ if rx == 1 and ry == 1 then
+ s = s_matrix_0
+ else
+ s = f_matrix_2(rx,ry)
+ end
+ else
+ s = f_matrix_4(rx,sx,sy,ry)
+ end
+ --
if shippingmode == "page" then
local tx = pos_h * (1 - rx) - pos_v * sy
local ty = pos_v * (1 - ry) - pos_h * sx
@@ -850,15 +861,7 @@ local flushsave, flushrestore, flushsetmatrix do
pdf_set_pos(pos_h,pos_v)
--
b = b + 1
- if sx == 0 and sy == 0 then
- if rx == 1 and ry == 1 then
- buffer[b] = s_matrix_0
- else
- buffer[b] = f_matrix_2(rx,ry)
- end
- else
- buffer[b] = f_matrix_4(rx,sx,sy,ry)
- end
+ buffer[b] = s
end
end
end
@@ -903,15 +906,15 @@ local localconverter = nil -- will be set
local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do
- local rulecodes = nodes.rulecodes
- local newrule = nodes.pool.rule
+ local rulecodes = nodes.rulecodes
+ local newrule = nodes.pool.rule
- local setprop = nuts.setprop
- local getprop = nuts.getprop
+ local setprop = nuts.setprop
+ local getprop = nuts.getprop
- local getwhd = nuts.getwhd
- local flushlist = nuts.flush_list
- local getdata = nuts.getdata
+ local getwhd = nuts.getwhd
+ local flushlist = nuts.flush_list
+ local getdata = nuts.getdata
local normalrule_code = rulecodes.normal
local boxrule_code = rulecodes.box
@@ -924,24 +927,24 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do
local radicalrule_code = rulecodes.radical
local outlinerule_code = rulecodes.outline
- local rule_callback = callbacks.functions.process_rule
+ local processrule = nodes.rules.process
local f_fm = formatters["/Fm%d Do"]
local f_im = formatters["/Im%d Do"]
local f_gr = formatters["/Gp%d Do"]
- local s_b = "q"
- local s_e = "Q"
+ local s_b = "q"
+ local s_e = "Q"
- local f_v = formatters["[] 0 d 0 J %.6N w 0 0 m %.6N 0 l S"]
- local f_h = formatters["[] 0 d 0 J %.6N w 0 0 m 0 %.6N l S"]
+ local f_v = formatters["[] 0 d 0 J %.6N w 0 0 m %.6N 0 l S"]
+ local f_h = formatters["[] 0 d 0 J %.6N w 0 0 m 0 %.6N l S"]
- local f_f = formatters["0 0 %.6N %.6N re f"]
- local f_o = formatters["[] 0 d 0 J 0 0 %.6N %.6N re S"]
- local f_w = formatters["[] 0 d 0 J %.6N w 0 0 %.6N %.6N re S"]
+ local f_f = formatters["0 0 %.6N %.6N re f"]
+ local f_o = formatters["[] 0 d 0 J 0 0 %.6N %.6N re S"]
+ local f_w = formatters["[] 0 d 0 J %.6N w 0 0 %.6N %.6N re S"]
- local f_b = formatters["%.6N w 0 %.6N %.6N %.6N re f"]
- local f_x = formatters["[] 0 d 0 J %.6N w %.6N %.6N %.6N %.6N re S"]
+ local f_b = formatters["%.6N w 0 %.6N %.6N %.6N re f"]
+ local f_x = formatters["[] 0 d 0 J %.6N w %.6N %.6N %.6N %.6N re S"]
-- Historically the index is an object which is kind of bad.
@@ -1291,7 +1294,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do
pdf_goto_pagemode()
b = b + 1 ; buffer[b] = s_b
pdf_set_pos_temp(pos_h,pos_v)
- rule_callback(current,size_h,size_v,pos_r) -- so we pass direction
+ processrule(current,size_h,size_v,pos_r) -- so we pass direction
b = b + 1 ; buffer[b] = s_e
return
end
diff --git a/tex/context/base/mkxl/lpdf-rul.lmt b/tex/context/base/mkxl/lpdf-rul.lmt
new file mode 100644
index 000000000..b3df0f0b7
--- /dev/null
+++ b/tex/context/base/mkxl/lpdf-rul.lmt
@@ -0,0 +1,392 @@
+if not modules then modules = { } end modules ['lpdf-rul'] = {
+ version = 1.001,
+ comment = "companion to grph-rul.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tonumber, next, type = tonumber, next, type
+local concat = table.concat
+
+local attributes = attributes
+local nodes = nodes
+
+local bpfactor = number.dimenfactors.bp
+
+local nuts = nodes.nuts
+local ruleactions = nuts.rules.ruleactions
+
+local getwhd = nuts.getwhd
+
+local lefttoright_code = nodes.dirvalues.lefttoright
+
+local mpcolor = attributes.colors.mpcolor
+
+local trace_mp = false trackers.register("rules.mp", function(v) trace_mp = v end)
+
+local report_mp = logs.reporter("rules","mp")
+
+local floor = math.floor
+local getrandom = utilities.randomizer.get
+local formatters = string.formatters
+
+-- This is very pdf specific. Maybe move some to lpdf-rul.lua some day.
+
+local pdfprint
+
+pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end
+
+-- updaters.register("backend.update",function()
+-- pdfprint = lpdf.print
+-- end)
+
+do
+
+ local simplemetapost = metapost.simple
+ local cachesize = 0
+ local maxcachesize = 256*1024
+ local cachethreshold = 1024
+ local caching = false -- otherwise random issues so we need a dedicated randomizer first
+
+ -- local maxcachesize = 8*1024
+ -- local cachethreshold = 1024/2
+
+ local cache = table.setmetatableindex(function(t,k)
+ local v = simplemetapost("rulefun",k) -- w, h, d
+ cachesize = cachesize + #v
+ if cachesize > maxcachesize then
+ -- print("old",cachesize)
+ for k, v in next, t do
+ local n = #v
+ if n > cachethreshold then
+ t[k] = nil
+ cachesize = cachesize - n
+ end
+ end
+ -- print("new",cachesize)
+ end
+ -- print(cachesize,maxcachesize,cachethreshold,#v)
+ t[k] = v
+ return v
+ end)
+
+ local replacer = utilities.templates.replacer
+
+ -- todo: RuleColor -> just string ?
+
+ local predefined = {
+ ["fake:word"] = replacer [[
+FakeWord(%width%,%height%,%depth%,%line%,%color%);
+ ]],
+ ["fake:rule"] = replacer[[
+%initializations%
+FakeRule(%width%,%height%,%depth%,%line%,%color%);
+ ]],
+ ["fake:rest"] = replacer [[
+RuleDirection := "%direction%" ;
+RuleOption := "%option%" ;
+RuleWidth := %width% ;
+RuleHeight := %height% ;
+RuleDepth := %depth% ;
+RuleH := %h% ;
+RuleV := %v% ;
+RuleThickness := %line% ;
+RuleFactor := %factor% ;
+RuleOffset := %offset% ;
+def RuleColor = %color% enddef ;
+%data%;
+ ]]
+ }
+
+ local initialized = false ;
+
+ rule_mp = function(p,h,v,i,n)
+ local name = p.name or "fake:rest"
+ local code = (predefined[name] or predefined["fake:rest"]) {
+ data = p.data or "",
+ width = p.width * bpfactor,
+ height = p.height * bpfactor,
+ depth = p.depth * bpfactor,
+ factor = (p.factor or 0) * bpfactor, -- needs checking
+ offset = p.offset or 0,
+ line = (p.line or 65536) * bpfactor,
+ color = mpcolor(p.ma,p.ca,p.ta),
+ option = p.option or "",
+ direction = p.direction or lefttoright_code,
+ h = h * bpfactor,
+ v = v * bpfactor,
+ }
+ if not initialized then
+ initialized = true
+ simplemetapost("rulefun",formatters["randomseed := %s;"](getrandom("rulefun",0,4095)))
+ end
+ -- we enable extensions but we could also consider to delegate colors
+ -- to the node finalizer
+ local pdf = caching and cache[code] or simplemetapost("rulefun",code,true)
+ if trace_mp then
+ report_mp("code: %s",code)
+ report_mp("pdf : %s",pdf)
+ end
+ if pdf and pdf ~= "" then
+ pdfprint("direct",pdf)
+ end
+ end
+
+ updaters.register("backend.update.lpdf",function()
+ ruleactions.mp = rule_mp
+ end)
+
+end
+
+do
+
+ -- This is the old oval method that we keep it for compatibility reasons. Of
+ -- course one can use mp instead. It could be improved but at the cost of more
+ -- code than I'm willing to add for something hardly used.
+
+ local function round(p,kind)
+ local method = tonumber(p.corner) or 0
+ if method < 0 or method > 27 then
+ method = 0
+ end
+ local width = p.width or 0
+ local height = p.height or 0
+ local depth = p.depth or 0
+ local total = height + depth
+ local radius = p.radius or 655360
+ local line = p.line or 65536
+ local how = (method > 8 or kind ~= "fill") and "S" or "f"
+ local half = line / 2
+ local xmin = half * bpfactor
+ local xmax = ( width - half) * bpfactor
+ local ymax = ( height - half) * bpfactor
+ local ymin = (-depth + half) * bpfactor
+ local full = ( radius + half)
+ local xxmin = full * bpfactor
+ local xxmax = ( width - full) * bpfactor
+ local yymax = ( height - full) * bpfactor
+ local yymin = (-depth + full) * bpfactor
+ line = line * bpfactor
+ if xxmin <= xxmax and yymin <= yymax then
+ local list = nil
+ if method == 0 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax,
+ xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
+ }
+ elseif method == 1 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, ymax, "l", xmin, ymax, "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
+ "h", how, "Q",
+ }
+ elseif method == 2 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
+ "l", xmin, ymax, xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin,
+ "y", "h", how, "Q",
+ }
+ elseif method == 3 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
+ xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin,
+ "l", "h", how, "Q",
+ }
+
+ elseif method == 4 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l",
+ "h", how, "Q",
+ }
+ elseif method == 5 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
+ xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 6 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, ymax, "l", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 7 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xmin, ymax,
+ "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
+ }
+ elseif method == 8 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
+ "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 9 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
+ xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y", xmax, ymax, "l", how, "Q",
+ }
+ elseif method == 10 then
+ list = {
+ "q", line, "w", xmax, ymax, "m", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y",
+ xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", xmax, ymin, "l", how, "Q",
+ }
+ elseif method == 11 then
+ list = {
+ "q", line, "w", xmax, ymin, "m", xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y",
+ xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 12 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
+ xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y", xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 13 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
+ xmax, ymin, "l", how, "Q",
+ }
+ elseif method == 14 then
+ list = {
+ "q", line, "w", xmax, ymax, "m", xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y",
+ xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 15 then
+ list = {
+ "q", line, "w", xmax, ymin, "m", xxmin, ymin, "l", xmin, ymin, xmin, yymin, "y",
+ xmin, ymax, "l", how, "Q",
+ }
+ elseif method == 16 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmin, yymax, "l", xmin, ymax, xxmin, ymax, "y",
+ xmax, ymax, "l", how, "Q",
+ }
+ elseif method == 17 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", how, "Q",
+ }
+ elseif method == 18 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", how, "Q",
+ }
+ elseif method == 19 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ elseif method == 20 then
+ list = {
+ "q", line, "w", xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 21 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 22 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
+ xmax, ymin, xxmax, ymin, "y", how, "Q",
+ }
+ elseif method == 23 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m",
+ xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ elseif method == 24 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 25 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
+ xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y",
+ xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 26 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+
+ elseif method == 27 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xxmin, ymin, "m",
+ xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ end
+ pdfprint("direct",concat(list," "))
+ end
+ end
+
+ local f_rectangle = formatters["%.6N w %.6N %.6N %.6N %.6N re %s"]
+ local f_baselined = formatters["%.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s"]
+ local f_dashlined = formatters["%.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s"]
+ local f_radtangle = formatters[
+[[%.6N w %.6N %.6N m
+%.6N %.6N l %.6N %.6N %.6N %.6N y
+%.6N %.6N l %.6N %.6N %.6N %.6N y
+%.6N %.6N l %.6N %.6N %.6N %.6N y
+%.6N %.6N l %.6N %.6N %.6N %.6N y
+h %s]]
+ ]
+
+ local rule_any = function(p,h,v,i,n)
+ if p.corner then
+ return round(p,i)
+ else
+ local l = (p.line or 65536)*bpfactor
+ local r = p and (p.radius or 0)*bpfactor or 0
+ local w = h * bpfactor
+ local h = v * bpfactor
+ local m = nil
+ local t = i == "fill" and "f" or "s"
+ local o = l / 2
+ if r > 0 then
+ w = w - o
+ h = h - o
+ m = f_radtangle(l, r,o, w-r,o, w,o,w,r, w,h-r, w,h,w-r,h, r,h, o,h,o,h-r, o,r, o,o,r,o, t)
+ else
+ w = w - l
+ h = h - l
+ m = f_rectangle(l,o,o,w,h,t)
+ end
+ pdfprint("direct",m)
+ end
+ end
+
+ local function rule_box(p,h,v,i,n)
+ local w, h, d = getwhd(n)
+ local line = p.line or 65536
+ local l = line *bpfactor
+ local w = w * bpfactor
+ local h = h * bpfactor
+ local d = d * bpfactor
+ local o = l / 2
+ if (d >= 0 and h >= 0) or (d <= 0 and h <= 0) then
+ local dashed = tonumber(p.dashed)
+ if dashed and dashed > 5*line then
+ dashed = dashed * bpfactor
+ local delta = (w - 2*dashed*floor(w/(2*dashed)))/2
+ pdfprint("direct",f_dashlined(l,o,o,w-l,h+d-l,dashed,dashed,delta,d,w-delta,d))
+ else
+ pdfprint("direct",f_baselined(l,o,o,w-l,h+d-l,0,d,w,d))
+ end
+ else
+ pdfprint("direct",f_rectangle(l,o,o,w-l,h+d-l))
+ end
+ end
+
+ updaters.register("backend.update.lpdf",function()
+ ruleactions.fill = rule_any
+ ruleactions.draw = rule_any
+ ruleactions.stroke = rule_any
+ ruleactions.box = rule_box
+ end)
+
+end
+
+
+ ruleactions.mp = unsupported
+
+
diff --git a/tex/context/base/mkxl/node-bck.lmt b/tex/context/base/mkxl/node-bck.lmt
new file mode 100644
index 000000000..9dff3ac40
--- /dev/null
+++ b/tex/context/base/mkxl/node-bck.lmt
@@ -0,0 +1,294 @@
+if not modules then modules = { } end modules ['node-bck'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to node-bck.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- beware, this one takes quite some runtime, so we need a status flag
+-- maybe some page related state
+
+-- todo: done (or just get rid of done altogether) ... saves no purpose
+-- any longer
+
+local attributes, nodes, node = attributes, nodes, node
+
+local enableaction = nodes.tasks.enableaction
+
+local nodecodes = nodes.nodecodes
+local listcodes = nodes.listcodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+
+local alignmentlist_code = listcodes.alignment
+local celllist_code = listcodes.cell
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local getsubtype = nuts.getsubtype
+local getwhd = nuts.getwhd
+local getwidth = nuts.getwidth
+local getprop = nuts.getprop
+
+local setattr = nuts.setattr
+local setlink = nuts.setlink
+local setlist = nuts.setlist
+local setattributelist = nuts.setattributelist
+local setprop = nuts.setprop
+
+local takebox = nuts.takebox
+local findtail = nuts.tail
+
+local nextnode = nuts.traversers.node
+local nexthlist = nuts.traversers.hlist
+local nextlist = nuts.traversers.list
+
+local flush_node_list = nuts.flush_list
+
+local new_rule = nodepool.rule
+local new_kern = nodepool.kern
+local new_hlist = nodepool.hlist
+
+local privateattributes = attributes.private
+local unsetvalue = attributes.unsetvalue
+
+local linefillers = nodes.linefillers
+
+local a_background = privateattributes("background")
+local a_alignbackground = privateattributes("alignbackground")
+local a_linefiller = privateattributes("linefiller")
+local a_ruled = privateattributes("ruled")
+
+local trace_alignment = false
+local report_alignment = logs.reporter("backgrounds","alignment")
+
+trackers.register("backgrounds.alignments",function(v) trace_alignment = v end)
+
+-- We can't use listbuilders with where=alignment because at that stage we have
+-- unset boxes. Also, post_linebreak is unsuitable for nested processing as we
+-- get the same stuff many times (wrapped again and again).
+--
+-- After many experiments with different callbacks the shipout is still the best
+-- place but then we need to store some settings longer or save them with the node.
+-- For color only we can get away with it with an extra attribute flagging a row
+-- but for more complex stuff we can better do as we do here now.
+
+local overshoot = math.floor(65781/5) -- could be an option per table (just also store it)
+
+local function colored_a(current,list,template,id)
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if width > 0 and total > 0 then
+ local rule = nil
+ --
+ local a = getattr(template,a_linefiller)
+ if a then
+ local d = linefillers.data[a%1000]
+ if d then
+ rule = linefillers.filler(template,d,width,height,depth)
+ end
+ end
+ --
+ if not rule then
+ rule = new_rule(width,height,depth)
+ setattributelist(rule,template)
+ end
+ local back = new_kern(-((id == vlist_code and total) or width))
+ return setlink(rule,back,list)
+ end
+end
+
+local function colored_b(current,list,template,id,indent)
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if width > 0 and total > 0 then
+ local fore = (indent ~= 0) and new_kern(indent)
+ local rule = nil
+ --
+ local a = getattr(template,a_linefiller)
+ if a then
+ local d = linefillers.data[a%1000]
+ if d then
+ rule = linefillers.filler(template,d,width-indent,height,depth)
+ end
+ end
+ --
+ if not rule then
+ rule = new_rule(width-indent,height+overshoot,depth+overshoot)
+ setattributelist(rule,template)
+ end
+ if overshoot == 0 then
+ local back = new_kern(-((id == vlist_code and total) or width))
+ return setlink(fore,rule,back,list)
+ else
+ rule = new_hlist(rule)
+ return setlink(fore,rule,list)
+ end
+ end
+end
+
+local templates = { }
+local currentrow = 0
+local enabled = false
+local alignments = false
+
+local function add_alignbackgrounds(head,list)
+ for current, id, subtype, list in nextlist, list do
+ if list and id == hlist_code and subtype == celllist_code then
+ for template in nexthlist, list do
+ local background = getattr(template,a_alignbackground)
+ if background then
+ local list = colored_a(current,list,template)
+ if list then
+ setlist(current,list)
+ end
+ setattr(template,a_alignbackground,unsetvalue) -- or property
+ end
+ break
+ end
+ end
+ end
+ local template = getprop(head,"alignmentchecked")
+ if template then
+ list = colored_b(head,list,template[1],hlist_code,template[2])
+ flush_node_list(template)
+ templates[currentrow] = false
+ return list
+ end
+end
+
+local function add_backgrounds(head,id,list)
+ if list then
+ for current, id, subtype, list in nextlist, list do
+ if list then
+ if alignments and subtype == alignmentlist_code then
+ local l = add_alignbackgrounds(current,list)
+ if l then
+ list = l
+ setlist(current,list)
+ end
+ end
+ local l = add_backgrounds(current,id,list)
+ if l then
+ list = l
+ setlist(current,l)
+ end
+ end
+ end
+ end
+ if id == hlist_code or id == vlist_code then
+ local background = getattr(head,a_background)
+ if background then
+ list = colored_a(head,list,head,id)
+ -- not needed
+ setattr(head,a_background,unsetvalue) -- or property -- todo
+ return list
+ end
+ end
+end
+
+function nodes.handlers.backgrounds(head)
+ add_backgrounds(head,getid(head),getlist(head))
+ return head
+end
+
+function nodes.handlers.backgroundspage(head,where)
+ if head and where == "alignment" then
+ for n in nexthlist, head do
+ local p = getprop(n,"alignmentchecked")
+ if not p and getsubtype(n) == alignmentlist_code then
+ currentrow = currentrow + 1
+ local template = templates[currentrow]
+ if trace_alignment then
+ report_alignment("%03i %s %s",currentrow,"page",template and "+" or "-")
+ end
+ setprop(n,"alignmentchecked",template)
+ end
+ end
+ end
+ return head
+end
+
+function nodes.handlers.backgroundsvbox(head,where)
+ if head and where == "vbox" then
+ local list = getlist(head)
+ if list then
+ for n in nexthlist, list do
+ local p = getprop(n,"alignmentchecked")
+ if not p and getsubtype(n) == alignmentlist_code then
+ currentrow = currentrow + 1
+ local template = templates[currentrow]
+ if trace_alignment then
+ report_alignment("%03i %s %s",currentrow,"vbox",template and "+" or "-")
+ end
+ setprop(n,"alignmentchecked",template)
+ end
+ end
+ end
+ end
+ return head
+end
+
+-- interfaces.implement {
+-- name = "enablebackgroundboxes",
+-- onlyonce = true,
+-- actions = enableaction,
+-- arguments = { "'shipouts'", "'nodes.handlers.backgrounds'" }
+-- }
+--
+-- doing it in the shipout works as well but this is nicer
+
+local function enable(alignmentstoo)
+ if not enabled then
+ enabled = true
+ enableaction("shipouts","nodes.handlers.backgrounds")
+ end
+ if not alignments and alignmentstoo then
+ alignments = true
+ enableaction("vboxbuilders","nodes.handlers.backgroundsvbox")
+ enableaction("mvlbuilders", "nodes.handlers.backgroundspage")
+ end
+end
+
+interfaces.implement {
+ name = "enablebackgroundboxes",
+ onlyonce = true,
+ actions = enable,
+}
+
+interfaces.implement {
+ name = "enablebackgroundalign",
+ onlyonce = true,
+ actions = function()
+ enable(true)
+ end,
+}
+
+interfaces.implement {
+ name = "setbackgroundrowdata",
+ arguments = { "integer", "integer", "dimension" },
+ actions = function(row,box,indent)
+ row = row -1 -- better here than in tex
+ if box == 0 then
+ templates[row] = false
+ else
+ templates[row] = { takebox(box), indent }
+ end
+ end,
+}
+
+interfaces.implement {
+ name = "resetbackgroundrowdata",
+ actions = function()
+ currentrow = 0
+ end,
+}
diff --git a/tex/context/base/mkxl/node-bck.mkxl b/tex/context/base/mkxl/node-bck.mkxl
index 0da516c88..b456313df 100644
--- a/tex/context/base/mkxl/node-bck.mkxl
+++ b/tex/context/base/mkxl/node-bck.mkxl
@@ -19,7 +19,7 @@
\unprotect
-\registerctxluafile{node-bck}{optimize}
+\registerctxluafile{node-bck}{autosuffix,optimize}
% \backgroundvbox[green] {\input tufte } \par
% \backgroundvbox[blue] {\input ward } \par
diff --git a/tex/context/base/mkxl/node-ini.mkxl b/tex/context/base/mkxl/node-ini.mkxl
index a7343469e..84f46e546 100644
--- a/tex/context/base/mkxl/node-ini.mkxl
+++ b/tex/context/base/mkxl/node-ini.mkxl
@@ -26,7 +26,7 @@
\registerctxluafile{node-aux}{autosuffix}
\registerctxluafile{node-gcm}{autosuffix}
\registerctxluafile{node-tst}{}
-\registerctxluafile{node-tra}{} % we might split it off (module)
+\registerctxluafile{node-tra}{autosuffix}
\registerctxluafile{node-snp}{autosuffix}
\registerctxluafile{node-tsk}{}
\registerctxluafile{node-tex}{autosuffix}
diff --git a/tex/context/base/mkxl/node-ref.lmt b/tex/context/base/mkxl/node-ref.lmt
index 98c600aa0..06c9981a9 100644
--- a/tex/context/base/mkxl/node-ref.lmt
+++ b/tex/context/base/mkxl/node-ref.lmt
@@ -425,15 +425,14 @@ end
local colorize, justadd do
- local a_color = attributes.private('color')
- local a_colormodel = attributes.private('colormodel')
- local a_transparency = attributes.private('transparency')
local u_transparency = nil
local u_colors = { }
local force_gray = true
local register_color = colors.register
+ local setcoloring = nuts.colors.set
+
local function addstring(what,str,shift) --todo make a pluggable helper (in font-ctx)
if str then
local typesetters = nuts.typesetters
@@ -486,10 +485,7 @@ local colorize, justadd do
height = 65536/2
depth = height
end
- local rule = new_rule(width,height,depth) -- todo: use tracer rule
- setattr(rule,a_colormodel,1) -- gray color model
- setattr(rule,a_color,u_color)
- setattr(rule,a_transparency,u_transparency)
+ local rule = setcoloring(new_rule(width,height,depth),1,u_color,u_transparency) -- gray color model
if width < 0 then
local kern = new_kern(width)
setwidth(rule,-width)
diff --git a/tex/context/base/mkxl/node-rul.lmt b/tex/context/base/mkxl/node-rul.lmt
index 72a257872..99c5d98a4 100644
--- a/tex/context/base/mkxl/node-rul.lmt
+++ b/tex/context/base/mkxl/node-rul.lmt
@@ -40,6 +40,7 @@ local getid = nuts.getid
local getdirection = nuts.getdirection
local getattr = nuts.getattr
local setattr = nuts.setattr
+local setattrs = nuts.setattrs
local getfont = nuts.getfont
local getsubtype = nuts.getsubtype
local getlist = nuts.getlist
@@ -67,7 +68,8 @@ local getrangedimensions = nuts.rangedimensions
local hpack_nodes = nuts.hpack
local copy_list = nuts.copy_list
-local nexthlist = nuts.traversers.hlist
+local nextlist = nuts.traversers.list
+local nextglue = nuts.traversers.glue
local nodecodes = nodes.nodecodes
local rulecodes = nodes.rulecodes
@@ -83,9 +85,11 @@ local hlist_code = nodecodes.hlist
local indentlist_code = listcodes.indent
local linelist_code = listcodes.line
-local leftskip_code = gluecodes.leftskip
-local rightskip_code = gluecodes.rightskip
-local parfillskip_code = gluecodes.parfillskip
+local leftskip_code = gluecodes.leftskip
+local rightskip_code = gluecodes.rightskip
+local parfillleftskip_code = gluecodes.parfillleftskip
+local parfillrightskip_code = gluecodes.parfillrightskip
+local indentskip_code = gluecodes.indentskip
local nodepool = nuts.pool
@@ -128,19 +132,17 @@ local setmetatableindex = table.setmetatableindex
local magicconstants = tex.magicconstants
local running = magicconstants.running
---
-
local striprange = nuts.striprange
local processwords = nuts.processwords
---
+local setcoloring = nuts.colors.set
-local rules = nodes.rules or { }
-nodes.rules = rules
-rules.data = rules.data or { }
+local rules = nodes.rules or { }
+nodes.rules = rules
+rules.data = rules.data or { }
-local nutrules = nuts.rules or { }
-nuts.rules = nutrules -- not that many
+local nutrules = nuts.rules or { }
+nuts.rules = nutrules -- not that many
storage.register("nodes/rules/data", rules.data, "nodes.rules.data")
@@ -211,8 +213,8 @@ local subtypeactions = {
[rulecodes.radical] = mathradical,
}
-local function process_rule(n,h,v)
- local n = tonut(n)
+function rules.process(n,h,v)
+ local n = tonut(n) -- already a nut
local s = getsubtype(n)
local a = subtypeactions[s]
if a then
@@ -220,10 +222,6 @@ local function process_rule(n,h,v)
end
end
-callbacks.register("process_rule",process_rule,"handle additional user rule features")
-
-callbacks.functions.process_rule = process_rule
-
--
local trace_ruled = false trackers.register("nodes.rules", function(v) trace_ruled = v end)
@@ -367,20 +365,9 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
else
for i=1,level do
local hd = (offset+(i-1)*dy)*e - m
--- local ht = hd + rulethickness - m
--- local dp = -hd + rulethickness + m
local ht = hd + rulethickness
local dp = -hd + rulethickness
- local r = new_rule(wd,ht,dp)
- -- can be done more efficient
- if color then
- setattr(r,a_colormodel,colorspace)
- setattr(r,a_color,color)
- end
- if transparency then
- setattr(r,a_transparency,transparency)
- end
- inject(r,wd,ht,dp)
+ inject(setcoloring(new_rule(wd,ht,dp),colorspace,color,transparency),wd,ht,dp)
end
end
end
@@ -489,15 +476,7 @@ local function linefiller(current,data,width,location)
direction = getdirection(current),
}
else
- local rule = new_rule(width,height,depth)
- if ca then
- setattr(rule,a_colorspace,ma)
- setattr(rule,a_color,ca)
- end
- if ta then
- setattr(rule,a_transparency,ta)
- end
- return rule
+ return setcoloring(new_rule(width,height,depth),ma,ca,ta)
end
end
@@ -525,35 +504,39 @@ function linefillers.filler(current,data,width,height,depth)
direction = getdirection(current),
}
else
- local rule = new_rule(width,height,depth)
- if ca then
- setattr(rule,a_colorspace,ma)
- setattr(rule,a_color,ca)
- end
- if ta then
- setattr(rule,a_transparency,ta)
- end
- return rule
+ return setcoloring(new_rule(width,height,depth),ma,ca,ta)
end
end
end
end
-local function find_attr(head,attr)
- while head do
- local a = head[attr]
- if a then
- return a, head
+local function getskips(list) -- this could be a helper
+ local ls = nil
+ local rs = nil
+ local is = nil
+ local pl = nil
+ local pr = nil
+ local ok = false
+ for n, subtype in nextglue, list do
+ if subtype == rightskip_code then
+ rs = n
+ elseif subtype == parfillrightskip_code then
+ pr = n
+ elseif subtype == leftskip_code then
+ ls = n
+ elseif subtype == indentskip_code then
+ is = n
+ elseif subtype == parfillleftskip_code then
+ pl = n
end
- head = getnext(head)
end
+ return is, ls, pl, pr, rs
end
function linefillers.handler(head)
- for current, subtype in nexthlist, head do
- if current and subtype == linelist_code then
- -- why doesn't leftskip take the attributes
- -- or list[linefiller] or maybe first match (maybe we need a fast helper for that)
+ -- we have a normalized line ..
+ for current, id, subtype, list in nextlist, head do
+ if subtype == linelist_code and list then
local a = getattr(current,a_linefiller)
if a then
local class = a % 1000
@@ -575,96 +558,44 @@ function linefillers.handler(head)
rightlocal = true
end
--
- local list = getlist(current)
- --
- if location == v_left or location == v_both then
- local lskip = nil -- leftskip
- local iskip = nil -- indentation
- local head = list
- while head do
- local id = getid(head)
- if id == glue_code then
- if getsubtype(head) == leftskip_code then
- lskip = head
- else
- break
- end
- elseif id == par_code or id == dir_code then
- -- go on
- elseif id == hlist_code then
- if getsubtype(head) == indentlist_code then
- iskip = head
- end
- break
- else
- break
- end
- head = getnext(head)
- end
- if head then
- local indentation = iskip and getwidth(iskip) or 0
- local leftfixed = lskip and getwidth(lskip) or 0
- local lefttotal = lskip and effective_glue(lskip,current) or 0
+ local is, ls, pl, pr, rs = getskips(list)
+ if ls and rs then
+ if location == v_left or location == v_both then
+ local indentation = is and getwidth(is) or 0
+ local leftfixed = ls and getwidth(ls) or 0
+ local lefttotal = ls and effective_glue(ls,current) or 0
local width = lefttotal - (leftlocal and leftfixed or 0) + indentation - distance
if width > threshold then
- if iskip then
- setwidth(iskip,0)
+ if is then
+ setwidth(is,0)
end
- if lskip then
- setglue(lskip,leftlocal and getwidth(lskip) or nil)
- if distance > 0 then
- insert_node_after(list,lskip,new_kern(distance))
- end
- insert_node_after(list,lskip,linefiller(current,data,width,"left"))
- else
- insert_node_before(list,head,linefiller(current,data,width,"left"))
- if distance > 0 then
- insert_node_before(list,head,new_kern(distance))
- end
+ setglue(ls,leftlocal and getwidth(ls) or nil)
+ if distance > 0 then
+ insert_node_after(list,ls,new_kern(distance))
end
+ insert_node_after(list,ls,linefiller(current,data,width,"left"))
end
end
- end
- --
- if location == v_right or location == v_both then
- local pskip = nil -- parfillskip
- local rskip = nil -- rightskip
- local tail = find_tail(list)
- while tail and getid(tail) == glue_code do
- local subtype = getsubtype(tail)
- if subtype == rightskip_code then
- rskip = tail
- elseif subtype == parfillskip_code then
- pskip = tail
- else
- break
- end
- tail = getprev(tail)
- end
- if tail then
- local rightfixed = rskip and getwidth(rskip) or 0
- local righttotal = rskip and effective_glue(rskip,current) or 0
- local parfixed = pskip and getwidth(pskip) or 0
- local partotal = pskip and effective_glue(pskip,current) or 0
+ --
+ if location == v_right or location == v_both then
+ local rightfixed = rs and getwidth(rs) or 0
+ local righttotal = rs and effective_glue(rs,current) or 0
+ local parfixed = pr and getwidth(pr) or 0
+ local partotal = pr and effective_glue(pr,current) or 0
local width = righttotal - (rightlocal and rightfixed or 0) + partotal - distance
if width > threshold then
- if pskip then
- setglue(pskip)
+ if pr then
+ setglue(pr)
end
- if rskip then
- setglue(rskip,rightlocal and getwidth(rskip) or nil)
- if distance > 0 then
- insert_node_before(list,rskip,new_kern(distance))
- end
- insert_node_before(list,rskip,linefiller(current,data,width,"right"))
- else
- insert_node_after(list,tail,linefiller(current,data,width,"right"))
- if distance > 0 then
- insert_node_after(list,tail,new_kern(distance))
- end
+ setglue(rs,rightlocal and getwidth(rs) or nil)
+ if distance > 0 then
+ insert_node_before(list,rs,new_kern(distance))
end
+ insert_node_before(list,rs,linefiller(current,data,width,"right"))
end
end
+ else
+ -- error, not a properly normalized line
end
end
end
diff --git a/tex/context/base/mkxl/node-rul.mkxl b/tex/context/base/mkxl/node-rul.mkxl
index a23867804..c507885a8 100644
--- a/tex/context/base/mkxl/node-rul.mkxl
+++ b/tex/context/base/mkxl/node-rul.mkxl
@@ -419,9 +419,6 @@
{\removeunwantedspaces
\endgroup}
-% \protected\def\node_shifts_direct#1%
-% {\doisolatedgroupedalign{\node_shifts_set{#1}}\donothing}
-
\protected\def\node_shifts_direct#1%
{\groupedcommand
{\begingroup\dostartisolation\begingroup\node_shifts_set{#1}\ignorespaces}
@@ -533,7 +530,7 @@
{\begingroup
\par
\def\currentlinefiller{#1}%
- \ifargument#2\or
+ \ifparameter#2\or
% we need to update settings
\setuplinefiller[#1][#2]% no \setupcurrentlinefiller as we need to update settings
\fi
diff --git a/tex/context/base/mkxl/node-tra.lmt b/tex/context/base/mkxl/node-tra.lmt
new file mode 100644
index 000000000..7b401361f
--- /dev/null
+++ b/tex/context/base/mkxl/node-tra.lmt
@@ -0,0 +1,734 @@
+if not modules then modules = { } end modules ['node-tra'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This is rather experimental. We need more control and some of this
+might become a runtime module instead. This module will be cleaned up!</p>
+--ldx]]--
+
+local next = next
+local utfchar = utf.char
+local format, match, gmatch, concat, rep = string.format, string.match, string.gmatch, table.concat, string.rep
+local lpegmatch = lpeg.match
+local clock = os.gettimeofday or os.clock -- should go in environment
+
+local report_nodes = logs.reporter("nodes","tracing")
+
+local nodes, node, context = nodes, node, context
+
+local texgetattribute = tex.getattribute
+
+local tracers = nodes.tracers or { }
+nodes.tracers = tracers
+
+local tasks = nodes.tasks or { }
+nodes.tasks = tasks
+
+local handlers = nodes.handlers or {}
+nodes.handlers = handlers
+
+local injections = nodes.injections or { }
+nodes.injections = injections
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getdisc = nuts.getdisc
+local setattr = nuts.setattr
+local setattrs = nuts.setattrs
+local getglue = nuts.getglue
+local isglyph = nuts.isglyph
+local getdirection = nuts.getdirection
+local getwidth = nuts.getwidth
+
+local flush_list = nuts.flush_list
+local count_nodes = nuts.countall
+local used_nodes = nuts.usedlist
+
+local nextnode = nuts.traversers.node
+local nextglyph = nuts.traversers.glyph
+
+local d_tostring = nuts.tostring
+
+local nutpool = nuts.pool
+local new_rule = nutpool.rule
+
+local nodecodes = nodes.nodecodes
+local whatsitcodes = nodes.whatsitcodes
+local fillcodes = nodes.fillcodes
+
+local subtypes = nodes.subtypes
+
+local glyph_code = nodecodes.glyph
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local disc_code = nodecodes.disc
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local rule_code = nodecodes.rule
+local dir_code = nodecodes.dir
+local par_code = nodecodes.par
+local whatsit_code = nodecodes.whatsit
+
+local dimenfactors = number.dimenfactors
+local formatters = string.formatters
+
+local start_of_par = nuts.start_of_par
+
+-- this will be reorganized:
+
+function nodes.showlist(head, message)
+ if message then
+ report_nodes(message)
+ end
+ for n in nextnode, tonut(head) do
+ report_nodes(d_tostring(n))
+ end
+end
+
+function nodes.handlers.checkglyphs(head,message)
+ local h = tonut(head) -- tonut needed?
+ local t = { }
+ local n = 0
+ local f = formatters["%U:%s"]
+ for g, char, font in nextglyph, h do
+ n = n + 1
+ t[n] = f(char,getsubtype(g))
+ end
+ if n == 0 then
+ -- nothing to report
+ elseif message and message ~= "" then
+ report_nodes("%s, %s glyphs: % t",message,n,t)
+ else
+ report_nodes("%s glyphs: % t",n,t)
+ end
+ return false
+end
+
+local fontcharacters -- = fonts.hashes.descriptions
+
+local function tosequence(start,stop,compact)
+ if start then
+ if not fontcharacters then
+ fontcharacters = fonts.hashes.descriptions
+ if not fontcharacters then
+ return "[no char data]"
+ end
+ end
+ local f_sequence = formatters["U+%04X:%s"]
+ local f_subrange = formatters["[[ %s ][ %s ][ %s ]]"]
+ start = tonut(start)
+ stop = stop and tonut(stop)
+ local t = { }
+ local n = 0
+ while start do
+ local c, id = isglyph(start)
+ if c then
+ local u = fontcharacters[id][c] -- id == font id
+ u = u and u.unicode or c
+ if type(u) == "table" then
+ local tt = { }
+ for i=1,#u do
+ local c = u[i]
+ tt[i] = compact and utfchar(c) or f_sequence(c,utfchar(c))
+ end
+ n = n + 1 ; t[n] = "(" .. concat(tt," ") .. ")"
+ else
+ n = n + 1 ; t[n] = compact and utfchar(c) or f_sequence(c,utfchar(c))
+ end
+ elseif id == disc_code then
+ local pre, post, replace = getdisc(start)
+ t[#t+1] = f_subrange(pre and tosequence(pre),post and tosequence(post),replace and tosequence(replace))
+ elseif id == rule_code then
+ n = n + 1 ; t[n] = compact and "|" or nodecodes[id] or "?"
+ elseif id == dir_code then
+ local d, p = getdirection(start)
+ n = n + 1 ; t[n] = "[<" .. (p and "-" or "+") .. d .. ">]" -- todo l2r etc
+ elseif id == par_code and start_of_par(current) then
+ n = n + 1 ; t[n] = "[<" .. getdirection(start) .. ">]" -- todo l2r etc
+ elseif compact then
+ n = n + 1 ; t[n] = "[]"
+ else
+ n = n + 1 ; t[n] = nodecodes[id]
+ end
+ if start == stop then
+ break
+ else
+ start = getnext(start)
+ end
+ end
+ if compact then
+ return concat(t)
+ else
+ return concat(t," ")
+ end
+ else
+ return "[empty]"
+ end
+end
+
+nodes.tosequence = tosequence
+nuts .tosequence = tosequence
+
+if CONTEXTLMTXMODE > 0 then
+
+ function nodes.report(t)
+ report_nodes("output %a, %s nodes",tex.getoutputactive(),count_nodes(t))
+ end
+
+else
+
+ function nodes.report(t)
+ report_nodes("output %a, %s nodes",status.output_active,count_nodes(t))
+ end
+
+end
+
+function nodes.packlist(head)
+ local t = { }
+ for n in nextnode, tonut(head) do
+ t[#t+1] = d_tostring(n)
+ end
+ return t
+end
+
+function nodes.idstostring(head,tail)
+ head = tonut(head)
+ tail = tail and tonut(tail)
+ local t = { }
+ local last_id = nil
+ local last_n = 0
+ local f_two = formatters["[%s*%s]"]
+ local f_one = formatters["[%s]"]
+ for n, id, subtype in nextnode, head do
+ if id == whatsit_code then
+ id = whatsitcodes[subtype]
+ else
+ id = nodecodes[id]
+ end
+ if not last_id then
+ last_id = id
+ last_n = 1
+ elseif last_id == id then
+ last_n = last_n + 1
+ else
+ if last_n > 1 then
+ t[#t+1] = f_two(last_n,last_id)
+ else
+ t[#t+1] = f_one(last_id)
+ end
+ last_id = id
+ last_n = 1
+ end
+ if n == tail then
+ break
+ end
+ end
+ if not last_id then
+ t[#t+1] = "no nodes"
+ else
+ if last_n > 1 then
+ t[#t+1] = f_two(last_n,last_id)
+ else
+ t[#t+1] = f_one(last_id)
+ end
+ end
+ return concat(t," ")
+end
+
+function nodes.idsandsubtypes(head)
+ local h = tonut(head)
+ local t = { }
+ local f = formatters["%s:%s"]
+ for n, id, subtype in nextnode, h do
+ local c = nodecodes[id]
+ if subtype then
+ t[#t+1] = f(c,subtypes[id][subtype])
+ else
+ t[#t+1] = c
+ end
+ end
+ return concat(t, " ")
+end
+
+-- function nodes.xidstostring(head,tail) -- only for special tracing of backlinks
+-- head = tonut(head)
+-- tail = tonut(tail)
+-- local n = head
+-- while n.next do
+-- n = n.next
+-- end
+-- local t, last_id, last_n = { }, nil, 0
+-- while n do
+-- local id = n.id
+-- if not last_id then
+-- last_id, last_n = id, 1
+-- elseif last_id == id then
+-- last_n = last_n + 1
+-- else
+-- if last_n > 1 then
+-- t[#t+1] = formatters["[%s*%s]"](last_n,nodecodes[last_id] or "?")
+-- else
+-- t[#t+1] = formatters["[%s]"](nodecodes[last_id] or "?")
+-- end
+-- last_id, last_n = id, 1
+-- end
+-- if n == head then
+-- break
+-- end
+-- n = getprev(n)
+-- end
+-- if not last_id then
+-- t[#t+1] = "no nodes"
+-- elseif last_n > 1 then
+-- t[#t+1] = formatters["[%s*%s]"](last_n,nodecodes[last_id] or "?")
+-- else
+-- t[#t+1] = formatters["[%s]"](nodecodes[last_id] or "?")
+-- end
+-- return table.concat(table.reversed(t)," ")
+-- end
+
+local function showsimplelist(h,depth,n)
+ h = h and tonut(h)
+ while h do
+ report_nodes("% w%s",n,d_tostring(h))
+ if not depth or n < depth then
+ local id = getid(h)
+ if id == hlist_code or id == vlist_code then
+ showsimplelist(getlist(h),depth,n+1)
+ end
+ end
+ h = getnext(h)
+ end
+end
+
+nodes.showsimplelist = function(h,depth) showsimplelist(h,depth,0) end
+
+local function listtoutf(h,joiner,textonly,last,nodisc)
+ local w = { }
+ local n = 0
+ local g = formatters["<%i>"]
+ local d = formatters["[%s|%s|%s]"]
+ while h do
+ local c, id = isglyph(h)
+ if c then
+ n = n + 1 ; w[n] = c >= 0 and utfchar(c) or g(c)
+ if joiner then
+ n = n + 1 ; w[n] = joiner
+ end
+ elseif id == disc_code then
+ local pre, pos, rep = getdisc(h)
+ if not nodisc then
+ n = n + 1 ; w[n] = d(
+ pre and listtoutf(pre,joiner,textonly) or "",
+ pos and listtoutf(pos,joiner,textonly) or "",
+ rep and listtoutf(rep,joiner,textonly) or ""
+ )
+ elseif rep then
+ n = n + 1 ; w[n] = listtoutf(rep,joiner,textonly) or ""
+ end
+ if joiner then
+ n = n + 1 ; w[n] = joiner
+ end
+ elseif textonly then
+ if id == glue_code then
+ if getwidth(h) > 0 then
+ n = n + 1 ; w[n] = " "
+ end
+ elseif id == hlist_code or id == vlist_code then
+ n = n + 1 ; w[n] = "["
+ n = n + 1 ; w[n] = listtoutf(getlist(h),joiner,textonly,last,nodisc)
+ n = n + 1 ; w[n] = "]"
+ end
+ else
+ n = n + 1 ; w[n] = "[-]"
+ end
+ if h == last then
+ break
+ else
+ h = getnext(h)
+ end
+ end
+ return concat(w,"",1,(w[n] == joiner) and (n-1) or n)
+end
+
+function nodes.listtoutf(h,joiner,textonly,last,nodisc)
+ if h then
+ local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
+ return listtoutf(tonut(h),joiner,textonly,last and tonut(last),nodisc)
+ else
+ return ""
+ end
+end
+
+local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" }
+
+local function showboxes(n,symbol,depth)
+ depth = depth or 0
+ symbol = symbol or "."
+ for n, id, subtype in nextnode, tonut(n) do
+ if id == hlist_code or id == vlist_code then
+ report_nodes(rep(symbol,depth) .. what[subtype] or subtype)
+ showboxes(getlist(n),symbol,depth+1)
+ end
+ end
+end
+
+nodes.showboxes = showboxes
+
+local ptfactor = dimenfactors.pt
+local bpfactor = dimenfactors.bp
+local stripper = lpeg.patterns.stripzeros
+
+local f_f_f = formatters["%0.5Fpt plus %0.5F%s minus %0.5F%s"]
+local f_f_m = formatters["%0.5Fpt plus %0.5F%s minus %0.5Fpt"]
+local f_p_f = formatters["%0.5Fpt plus %0.5Fpt minus %0.5F%s"]
+local f_p_m = formatters["%0.5Fpt plus %0.5Fpt minus %0.5Fpt"]
+local f_f_z = formatters["%0.5Fpt plus %0.5F%s"]
+local f_p_z = formatters["%0.5Fpt plus %0.5Fpt"]
+local f_z_f = formatters["%0.5Fpt minus %0.5F%s"]
+local f_z_m = formatters["%0.5Fpt minus %0.5Fpt"]
+local f_z_z = formatters["%0.5Fpt"]
+
+local tonut = nodes.tonut
+
+local function nodetodimen(n)
+ n = tonut(n)
+ local id = getid(n)
+ if id == kern_code then
+ local width = getwidth(n)
+ if width == 0 then
+ return "0pt"
+ else
+ return f_z_z(width)
+ end
+ elseif id ~= glue_code then
+ return "0pt"
+ end
+ local width, stretch, shrink, stretch_order, shrink_order = getglue(n)
+ stretch = stretch / 65536
+ shrink = shrink / 65536
+ width = width / 65536
+ if stretch_order ~= 0 then
+ if shrink_order ~= 0 then
+ return f_f_f(width,stretch,fillcodes[stretch_order],shrink,fillcodes[shrink_order])
+ elseif shrink ~= 0 then
+ return f_f_m(width,stretch,fillcodes[stretch_order],shrink)
+ else
+ return f_f_z(width,stretch,fillcodes[stretch_order])
+ end
+ elseif shrink_order ~= 0 then
+ if stretch ~= 0 then
+ return f_p_f(width,stretch,shrink,fillcodes[shrink_order])
+ else
+ return f_z_f(width,shrink,fillcodes[shrink_order])
+ end
+ elseif stretch ~= 0 then
+ if shrink ~= 0 then
+ return f_p_m(width,stretch,shrink)
+ else
+ return f_p_z(width,stretch)
+ end
+ elseif shrink ~= 0 then
+ return f_z_m(width,shrink)
+ elseif width == 0 then
+ return "0pt"
+ else
+ return f_z_z(width)
+ end
+end
+
+
+-- number.todimen(123)
+-- number.todimen(123,"cm")
+-- number.todimen(123,false,"%F))
+
+local f_pt = formatters["%p"]
+local f_un = formatters["%F%s"]
+
+dimenfactors[""] = dimenfactors.pt
+
+local function numbertodimen(d,unit,fmt)
+ if not d or d == 0 then
+ if fmt then
+ return formatters[fmt](0,unit or "pt")
+ elseif unit then
+ return 0 .. unit
+ else
+ return "0pt"
+ end
+ elseif fmt then
+ if not unit then
+ unit = "pt"
+ end
+ return formatters[fmt](d*dimenfactors[unit],unit)
+ elseif not unit or unit == "pt" then
+ return f_pt(d)
+ else
+ return f_un(d*dimenfactors[unit],unit)
+ end
+end
+
+number.todimen = numbertodimen
+nodes .todimen = nodetodimen
+
+function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end
+function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end
+function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end
+function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end
+function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end
+function number.toscaledpoints(n) return n .. "sp" end
+function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end
+function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end
+function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end
+function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end
+-------- number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end
+-------- number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end
+
+function nodes.topoints (n,fmt) return nodetodimen(n,"pt",fmt) end
+function nodes.toinches (n,fmt) return nodetodimen(n,"in",fmt) end
+function nodes.tocentimeters (n,fmt) return nodetodimen(n,"cm",fmt) end
+function nodes.tomillimeters (n,fmt) return nodetodimen(n,"mm",fmt) end
+function nodes.toscaledpoints(n,fmt) return nodetodimen(n,"sp",fmt) end
+function nodes.toscaledpoints(n) return n .. "sp" end
+function nodes.tobasepoints (n,fmt) return nodetodimen(n,"bp",fmt) end
+function nodes.topicas (n,fmt) return nodetodimen(n "pc",fmt) end
+function nodes.todidots (n,fmt) return nodetodimen(n,"dd",fmt) end
+function nodes.tociceros (n,fmt) return nodetodimen(n,"cc",fmt) end
+-------- nodes.tonewdidots (n,fmt) return nodetodimen(n,"nd",fmt) end
+-------- nodes.tonewciceros (n,fmt) return nodetodimen(n,"nc",fmt) end
+
+-- stop redefinition
+
+local points = function(n)
+ if not n or n == 0 then
+ return "0pt"
+ elseif type(n) == "number" then
+ return lpegmatch(stripper,format("%.5fpt",n*ptfactor)) -- faster than formatter
+ else
+ return numbertodimen(n,"pt") -- also deals with nodes
+ end
+end
+
+local basepoints = function(n)
+ if not n or n == 0 then
+ return "0bp"
+ elseif type(n) == "number" then
+ return lpegmatch(stripper,format("%.5fbp",n*bpfactor)) -- faster than formatter
+ else
+ return numbertodimen(n,"bp") -- also deals with nodes
+ end
+end
+
+local pts = function(n)
+ if not n or n == 0 then
+ return "0pt"
+ elseif type(n) == "number" then
+ return format("%.5fpt",n*ptfactor) -- faster than formatter
+ else
+ return numbertodimen(n,"pt") -- also deals with nodes
+ end
+end
+
+local nopts = function(n)
+ if not n or n == 0 then
+ return "0"
+ else
+ return format("%.5f",n*ptfactor) -- faster than formatter
+ end
+end
+
+number.points = points
+number.basepoints = basepoints
+number.pts = pts
+number.nopts = nopts
+
+nodes.points = function(n) return numbertodimen(n,"pt") end
+nodes.basepoints = function(n) return numbertodimen(n,"bp") end
+nodes.pts = function(n) return numbertodimen(n,"pt") end
+nodes.nopts = function(n) return format("%.5f",n*ptfactor) end
+
+local colors = { }
+tracers.colors = colors
+
+local unsetvalue = attributes.unsetvalue
+
+local a_color = attributes.private('color')
+local a_colormodel = attributes.private('colormodel')
+local m_color = attributes.list[a_color] or { }
+
+function colors.set(n,c,s,t) -- also unsets !
+ local mc = m_color[c]
+ local nn = tonut(n)
+ if mc then
+ local mm = s or texgetattribute(a_colormodel)
+ if mm <= 0 then
+ mm = 1
+ end
+ -- only here t is dealt with
+ if t then
+ setattrs(nn,a_colormodel,mm,a_color,mc,a_transparency,m_transparency[t] or unsetvalue)
+ else
+ setattrs(nn,a_colormodel,mm,a_color,mc)
+ end
+ else
+ setattr(nn,a_color,unsetvalue)
+ end
+ return n
+end
+
+function colors.setlist(n,c,s,t)
+ local nn = tonut(n)
+ local mc = m_color[c] or unsetvalue
+ local mm = s or texgetattribute(a_colormodel)
+ if mm <= 0 then
+ mm = 1
+ end
+ if t then
+ t = m_transparency[t] or unsetvalue
+ while nn do
+ setattrs(nn,a_colormodel,mm,a_color,mc,a_transparency,t)
+ nn = getnext(nn)
+ end
+ else
+ while nn do
+ setattrs(nn,a_colormodel,mm,a_color,mc)
+ nn = getnext(nn)
+ end
+ end
+ return n
+end
+
+function colors.reset(n)
+ setattr(tonut(n),a_color,unsetvalue)
+ return n
+end
+
+-- maybe
+
+local transparencies = { }
+tracers.transparencies = transparencies
+
+local a_transparency = attributes.private('transparency')
+local m_transparency = attributes.list[a_transparency] or { }
+
+function transparencies.set(n,t)
+ setattr(tonut(n),a_transparency,m_transparency[t] or unsetvalue)
+ return n
+end
+
+function transparencies.setlist(n,c,s)
+ local nn = tonut(n)
+ local mt = m_transparency[c] or unsetvalue
+ while nn do
+ setattr(nn,a_transparency,mt)
+ nn = getnext(nn)
+ end
+ return n
+end
+
+function transparencies.reset(n)
+ setattr(n,a_transparency,unsetvalue)
+ return n
+end
+
+-- for the moment here
+
+local visualizers = nodes.visualizers or { }
+nodes.visualizers = visualizers
+
+function visualizers.handler(head)
+ return head, false
+end
+
+-- we could cache attribute lists and set attr (copy will increment count) .. todo ..
+-- although tracers are used seldom
+
+local function setproperties(n,c,s)
+ local nn = tonut(n)
+ local mm = texgetattribute(a_colormodel)
+ setattr(nn,a_colormodel,mm > 0 and mm or 1)
+ setattr(nn,a_color,m_color[c])
+ setattr(nn,a_transparency,m_transparency[c])
+ return n
+end
+
+tracers.setproperties = setproperties
+
+-- setting attrlist entries instead of attr for successive entries doesn't
+-- speed up much (this function is only used in tracers anyway)
+
+function tracers.setlist(n,c,s)
+ local nn = tonut(n)
+ local mc = m_color[c]
+ local mt = m_transparency[c]
+ local mm = texgetattribute(a_colormodel)
+ if mm <= 0 then
+ mm = 1
+ end
+ while nn do
+ setattr(nn,a_colormodel,mm)
+ setattr(nn,a_color,mc)
+ setattr(nn,a_transparency,mt)
+ nn = getnext(nn)
+ end
+ return n
+end
+
+function tracers.resetproperties(n)
+ local nn = tonut(n)
+ setattr(nn,a_color,unsetvalue)
+ setattr(nn,a_transparency,unsetvalue)
+ return n
+end
+
+-- this one returns a nut
+
+local nodestracerpool = { }
+local nutstracerpool = { }
+
+tracers.pool = {
+ nodes = nodestracerpool,
+ nuts = nutstracerpool,
+}
+
+table.setmetatableindex(nodestracerpool,function(t,k,v)
+ local f = nutstracerpool[k]
+ local v = function(...)
+ return tonode(f(...))
+ end
+ t[k] = v
+ return v
+end)
+
+function nutstracerpool.rule(w,h,d,c,s) -- so some day we can consider using literals (speedup)
+ return setproperties(new_rule(w,h,d),c,s)
+end
+
+tracers.rule = nodestracerpool.rule -- for a while
+
+-- local function show(head,n,message)
+-- print("START",message or "")
+-- local i = 0
+-- for current in traverse(head) do
+-- local prev = getprev(current)
+-- local next = getnext(current)
+-- i = i + 1
+-- print(i, prev and nodecodes[getid(prev)],nodecodes[getid(current)],next and nodecodes[getid(next)])
+-- if i == n then
+-- break
+-- end
+-- end
+-- print("STOP", message or "")
+-- end
diff --git a/tex/context/base/mkxl/typo-drp.lmt b/tex/context/base/mkxl/typo-drp.lmt
new file mode 100644
index 000000000..8741376b6
--- /dev/null
+++ b/tex/context/base/mkxl/typo-drp.lmt
@@ -0,0 +1,346 @@
+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 one is sensitive for order (e.g. when combined with first line
+-- processing.
+
+-- todo: use isglyph
+
+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 enableaction = tasks.enableaction
+local disableaction = tasks.disableaction
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getwhd = nuts.getwhd
+
+local getprop = nuts.getprop
+local setprop = nuts.setprop
+
+local setlink = nuts.setlink
+local setprev = nuts.setprev
+local setnext = nuts.setnext
+local setfont = nuts.setfont
+local setchar = nuts.setchar
+local setwhd = nuts.setwhd
+local setkern = nuts.setkern
+local setoffsets = nuts.setoffsets
+local setglyphdata = nuts.setglyphdata
+
+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 start_of_par = nuts.start_of_par
+
+local nextnode = nuts.traversers.node
+local nextglyph = nuts.traversers.glyph
+
+local setcoloring = nuts.colors.set
+
+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 texset = tex.set
+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 par_code = nodecodes.par
+
+local actions = { }
+initials.actions = actions
+
+local a_initial = attributes.private("initial")
+
+local category = characters.category
+
+local function set(par,specification)
+ enableaction("processors","typesetters.initials.handler")
+ if trace_initials then
+ report_initials("enabling initials")
+ end
+ setprop(par,a_initial,specification)
+end
+
+function initials.set(specification)
+ nuts.setparproperty(set,specification)
+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" },
+ }
+ }
+}
+
+-- 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)
+ -- 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 = texget("parindent")
+ local baseline = texget("baselineskip",false)
+ 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 nextnode, 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
+ end
+ last = nil
+ for current in nextglyph, 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
+ 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
+ end
+ for current in nextglyph, next do
+ last = current
+ break
+ end
+ if last == first then
+ return head
+ 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, char in nextglyph, next do
+ 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 nextglyph, 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
+ setkern(current,0)
+ elseif id == glyph_code then
+ local next = getnext(current)
+ if font then
+ setfont(current,font)
+ end
+ if dynamic > 0 then
+ setglyphdata(current,dynamic)
+ end
+ setcoloring(ma,ca,ta)
+ 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 par).
+ local prev = getprev(first)
+ local next = getnext(last)
+ --
+ setprev(first)
+ setnext(last)
+ local dropper = hpack_nodes(first)
+ local width, height, depth = getwhd(dropper)
+ setwhd(dropper,0,0,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 nextglyph, first do
+ setoffsets(current,-hoffset,-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
+ if CONTEXTLMTXMODE > 0 then
+ texset("hangafter",hangafter,true)
+ texset("hangindent",hangindent,true)
+ else
+ texset("hangafter",hangafter)
+ texset("hangindent",hangindent)
+ end
+ end
+ if indent then
+ insert_after(first,first,new_kern(-parindent))
+ end
+ end
+ return head
+end
+
+-- we can count ... when all done, we can disable ...
+
+function initials.handler(head)
+ if getid(head) == par_code and start_of_par(head) then
+ local settings = getprop(head,a_initial)
+ if settings then
+ disableaction("processors","typesetters.initials.handler")
+ 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
+ return action(head,settings)
+ end
+ end
+ end
+ return head
+end
diff --git a/tex/context/base/mkxl/typo-drp.mkxl b/tex/context/base/mkxl/typo-drp.mkxl
index 9a6ae7603..94e08c9b0 100644
--- a/tex/context/base/mkxl/typo-drp.mkxl
+++ b/tex/context/base/mkxl/typo-drp.mkxl
@@ -17,7 +17,7 @@
\unprotect
-\registerctxluafile{typo-drp}{}
+\registerctxluafile{typo-drp}{autosuffix}
\definesystemattribute[initial][public]
diff --git a/tex/context/base/mkxl/typo-fln.lmt b/tex/context/base/mkxl/typo-fln.lmt
new file mode 100644
index 000000000..fa507df4b
--- /dev/null
+++ b/tex/context/base/mkxl/typo-fln.lmt
@@ -0,0 +1,406 @@
+if not modules then modules = { } end modules ['typo-fln'] = {
+ version = 1.001,
+ comment = "companion to typo-fln.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- When I ran into the following experimental code again, I figured that it dated
+-- from the early days of mkiv, so I updates it a bit to fit into todays context.
+-- In the process I might have messed up things. For instance we had a diffent
+-- wrapper then using head and tail.
+
+-- todo: only letters (no punctuation)
+-- todo: nuts
+
+local trace_firstlines = false trackers.register("typesetters.firstlines", function(v) trace_firstlines = v end)
+local report_firstlines = logs.reporter("nodes","firstlines")
+
+typesetters.firstlines = typesetters.firstlines or { }
+local firstlines = typesetters.firstlines
+
+local nodes = nodes
+
+local tasks = nodes.tasks
+local enableaction = tasks.enableaction
+local disableaction = tasks.disableaction
+
+local context = context
+local implement = interfaces.implement
+
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getboth = nuts.getboth
+local setboth = nuts.setboth
+local getid = nuts.getid
+local getwidth = nuts.getwidth
+local getlist = nuts.getlist
+local setlist = nuts.setlist
+local getattr = nuts.getattr
+local getbox = nuts.getbox
+local getdisc = nuts.getdisc
+local setdisc = nuts.setdisc
+local setlink = nuts.setlink
+local setfont = nuts.setfont
+local setglyphdata = nuts.setglyphdata
+local getprop = nuts.getprop
+local setprop = nuts.setprop
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local par_code = nodecodes.par
+
+local spaceskip_code = nodes.gluecodes.spaceskip
+
+local nextglyph = nuts.traversers.glyph
+local nextdisc = nuts.traversers.disc
+
+local flush_node_list = nuts.flush_list
+local flush_node = nuts.flush_node
+local copy_node_list = nuts.copy_list
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local getdimensions = nuts.dimensions
+local hpack_node_list = nuts.hpack
+local start_of_par = nuts.start_of_par
+
+local setcoloring = nuts.colors.set
+
+local nodepool = nuts.pool
+local newpenalty = nodepool.penalty
+local newkern = nodepool.kern
+local tracerrule = nodes.tracers.pool.nuts.rule
+
+local actions = { }
+firstlines.actions = actions
+
+local a_firstline = attributes.private('firstline')
+
+local texget = tex.get
+
+local variables = interfaces.variables
+local v_default = variables.default
+local v_line = variables.line
+local v_word = variables.word
+
+local function set(par,specification)
+ enableaction("processors","typesetters.firstlines.handler")
+ if trace_firstlines then
+ report_firstlines("enabling firstlines")
+ end
+ setprop(par,a_firstline,specification)
+end
+
+function firstlines.set(specification)
+ nuts.setparproperty(set,specification)
+end
+
+implement {
+ name = "setfirstline",
+ actions = firstlines.set,
+ arguments = {
+ {
+ { "alternative" },
+ { "font", "integer" },
+ { "dynamic", "integer" },
+ { "ma", "integer" },
+ { "ca", "integer" },
+ { "ta", "integer" },
+ { "n", "integer" },
+ }
+ }
+}
+
+actions[v_line] = function(head,setting)
+ local dynamic = setting.dynamic
+ local font = setting.font
+ local noflines = setting.n or 1
+ local ma = setting.ma or 0
+ local ca = setting.ca
+ local ta = setting.ta
+ local hangafter = texget("hangafter")
+ local hangindent = texget("hangindent")
+ local parindent = texget("parindent")
+ local nofchars = 0
+ local n = 0
+ local temp = copy_node_list(head)
+ local linebreaks = { }
+
+ local set = function(head)
+ for g in nextglyph, head do
+ if dynamic > 0 then
+ setglyphdata(g,dynamic)
+ end
+ setfont(g,font)
+ end
+ end
+
+ set(temp)
+
+ for g in nextdisc, temp do
+ local pre, post, replace = getdisc(g)
+ if pre then
+ set(pre)
+ end
+ if post then
+ set(post)
+ end
+ if replace then
+ set(replace)
+ end
+ end
+
+ local start = temp
+ local list = temp
+ local prev = temp
+ for i=1,noflines do
+ local hsize = texget("hsize") - texget("leftskip",false) - texget("rightskip",false)
+ if i == 1 then
+ hsize = hsize - parindent
+ end
+ if i <= - hangafter then
+ hsize = hsize - hangindent
+ end
+
+ local function list_dimensions(list,start)
+ local temp = copy_node_list(list,start)
+ temp = nodes.handlers.characters(temp)
+ temp = nodes.injections.handler(temp)
+ -- temp = typesetters.fontkerns.handler(temp) -- maybe when enabled
+ -- nodes.handlers.protectglyphs(temp) -- not needed as we discard
+ -- temp = typesetters.spacings.handler(temp) -- maybe when enabled
+ -- temp = typesetters.kerns.handler(temp) -- maybe when enabled
+ -- temp = typesetters.cases.handler(temp) -- maybe when enabled
+ local width = getdimensions(temp)
+ flush_node_list(temp)
+ return width
+ end
+
+ local function try(extra)
+ local width = list_dimensions(list,start)
+ if extra then
+ width = width + list_dimensions(extra)
+ end
+ -- report_firstlines("line length: %p, progression: %p, text: %s",hsize,width,nodes.listtoutf(list,nil,nil,start))
+ if width > hsize then
+ list = prev
+ return true
+ else
+ linebreaks[i] = n
+ prev = start
+ nofchars = n
+ end
+ end
+
+ while start do
+ local id = getid(start)
+ if id == glyph_code then
+ -- go on
+ elseif id == disc_code then
+ -- this could be an option
+ n = n + 1
+ local pre, post, replace = getdisc(start)
+ if pre and try(pre) then
+ break
+ elseif replace and try(replace) then
+ break
+ end
+ elseif id == kern_code then -- todo: fontkern
+ -- this could be an option
+ elseif id == glue_code then
+ n = n + 1
+ if try() then
+ break
+ end
+ end
+ start = getnext(start)
+ end
+ if not linebreaks[i] then
+ linebreaks[i] = n
+ end
+ end
+
+ flush_node_list(temp)
+
+ local start = head
+ local n = 0
+
+ local function update(start)
+ if dynamic > 0 then
+ setglyphdata(start,dynamic)
+ end
+ setfont(start,font)
+ setcoloring(ma,ca,ta)
+ end
+
+ for i=1,noflines do
+ local linebreak = linebreaks[i]
+ while start and n < nofchars do
+ local id = getid(start)
+ local ok = false
+ if id == glyph_code then
+ update(start)
+ elseif id == disc_code then
+ n = n + 1
+ local disc = start
+ local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
+ if linebreak == n then
+ local p, n = getboth(start)
+ if pre then
+ for current in nextglyph, pre do
+ update(current)
+ end
+ setlink(pretail,n)
+ setlink(p,pre)
+ start = pretail
+ pre = nil
+ else
+ setlink(p,n)
+ start = p
+ end
+ if post then
+ local p, n = getboth(start)
+ setlink(posttail,n)
+ setlink(start,post)
+ post = nil
+ end
+ else
+ local p, n = getboth(start)
+ if replace then
+ for current in nextglyph, replace do
+ update(current)
+ end
+ setlink(replacetail,n)
+ setlink(p,replace)
+ start = replacetail
+ replace = nil
+ else
+ setlink(p,n)
+ start = p
+ end
+ end
+ setdisc(disc,pre,post,replace)
+ flush_node(disc)
+ elseif id == glue_code then
+ n = n + 1
+ if linebreak ~= n then
+ head = insert_node_before(head,start,newpenalty(10000)) -- nobreak
+ end
+ end
+ local next = getnext(start)
+ if linebreak == n then
+ if start ~= head then
+ local where = id == glue_code and getprev(start) or start
+ if trace_firstlines then
+ head, where = insert_node_after(head,where,newpenalty(10000)) -- nobreak
+ head, where = insert_node_after(head,where,newkern(-65536))
+ head, where = insert_node_after(head,where,tracerrule(65536,4*65536,2*65536,"darkblue"))
+ end
+ head, where = insert_node_after(head,where,newpenalty(-10000)) -- break
+ end
+ start = next
+ break
+ end
+ start = next
+ end
+ end
+
+ return head
+end
+
+actions[v_word] = function(head,setting)
+ -- local attribute = fonts.specifiers.contextnumber(setting.feature) -- was experimental
+ local dynamic = setting.dynamic
+ local font = setting.font
+ local words = 0
+ local nofwords = setting.n or 1
+ local start = head
+ local ok = false
+ local ma = setting.ma or 0
+ local ca = setting.ca
+ local ta = setting.ta
+ while start do
+ local id = getid(start)
+ -- todo: delete disc nodes
+ if id == glyph_code then
+ if not ok then
+ words = words + 1
+ ok = true
+ end
+ setcoloring(ma,ca,ta)
+ if dynamic > 0 then
+ setglyphdata(start,dynamic)
+ end
+ setfont(start,font)
+ elseif id == disc_code then
+ -- continue
+ elseif id == kern_code then -- todo: fontkern
+ -- continue
+ else
+ ok = false
+ if words == nofwords then
+ break
+ end
+ end
+ start = getnext(start)
+ end
+ return head
+end
+
+actions[v_default] = actions[v_line]
+
+function firstlines.handler(head)
+ if getid(head) == par_code and start_of_par(head) then
+ local settings = getprop(head,a_firstline)
+ if settings then
+ disableaction("processors","typesetters.firstlines.handler")
+ local alternative = settings.alternative or v_default
+ local action = actions[alternative] or actions[v_default]
+ if action then
+ if trace_firstlines then
+ report_firstlines("processing firstlines, alternative %a",alternative)
+ end
+ return action(head,settings)
+ end
+ end
+ end
+ return head
+end
+
+-- goodie
+
+local function applytofirstcharacter(box,what)
+ local tbox = getbox(box) -- assumes hlist
+ local list = getlist(tbox)
+ local done = nil
+ for n in nextglyph, list do
+ list = remove_node(list,n)
+ done = n
+ break
+ end
+ if done then
+ setlist(tbox,list)
+ local kind = type(what)
+ if kind == "string" then
+ context[what](tonode(done))
+ elseif kind == "function" then
+ what(done)
+ else
+ -- error
+ end
+ end
+end
+
+implement {
+ name = "applytofirstcharacter",
+ actions = applytofirstcharacter,
+ arguments = { "integer", "string" }
+}
diff --git a/tex/context/base/mkxl/typo-fln.mkxl b/tex/context/base/mkxl/typo-fln.mkxl
index 2696dd06b..3ef688bb5 100644
--- a/tex/context/base/mkxl/typo-fln.mkxl
+++ b/tex/context/base/mkxl/typo-fln.mkxl
@@ -50,7 +50,7 @@
\unprotect
-\registerctxluafile{typo-fln}{}
+\registerctxluafile{typo-fln}{autosuffix}
\definesystemattribute[firstline][public]
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 9515034ab..7fb03eb1e 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 2020-12-04 20:19
+-- merge date : 2020-12-06 18:12
do -- begin closure to overcome local limits and interference