summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2020-12-04 21:16:33 +0100
committerContext Git Mirror Bot <phg@phi-gamma.net>2020-12-04 21:16:33 +0100
commit0477f879e2b574ad568732ad03784e5df1952fb7 (patch)
tree01fce60ad825be975aa127379edaef3d3f24d6c5 /tex
parent61848324b49c6fe34f9c5dd62a34d2fbfbbb16b8 (diff)
downloadcontext-0477f879e2b574ad568732ad03784e5df1952fb7.tar.gz
2020-12-04 20:21: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/status-files.pdfbin26093 -> 26096 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin255687 -> 255677 bytes
-rw-r--r--tex/context/base/mkiv/typo-spa.lua246
-rw-r--r--tex/context/base/mkxl/back-out.lmt4
-rw-r--r--tex/context/base/mkxl/back-trf.lmt8
-rw-r--r--tex/context/base/mkxl/cont-log.mkxl2
-rw-r--r--tex/context/base/mkxl/cont-new.mkxl2
-rw-r--r--tex/context/base/mkxl/context.mkxl2
-rw-r--r--tex/context/base/mkxl/grph-inc.mkxl6
-rw-r--r--tex/context/base/mkxl/lpdf-lmt.lmt7
-rw-r--r--tex/context/base/mkxl/lpdf-tag.lmt3
-rw-r--r--tex/context/base/mkxl/meta-ini.mkxl2
-rw-r--r--tex/context/base/mkxl/node-nut.lmt1
-rw-r--r--tex/context/base/mkxl/page-bck.mkxl4
-rw-r--r--tex/context/base/mkxl/syst-ini.mkxl9
-rw-r--r--tex/context/base/mkxl/tabl-tbl.mkxl8
-rw-r--r--tex/context/base/mkxl/typo-brk.lmt498
-rw-r--r--tex/context/base/mkxl/typo-brk.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-cap.lmt272
-rw-r--r--tex/context/base/mkxl/typo-cap.mkxl3
-rw-r--r--tex/context/base/mkxl/typo-dig.lmt181
-rw-r--r--tex/context/base/mkxl/typo-dig.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-krn.lmt630
-rw-r--r--tex/context/base/mkxl/typo-krn.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-pag.lmt206
-rw-r--r--tex/context/base/mkxl/typo-pag.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-spa.lmt255
-rw-r--r--tex/context/base/mkxl/typo-spa.mkxl2
-rw-r--r--tex/context/modules/mkiv/s-magazine-basic.mkiv7
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua2
34 files changed, 1947 insertions, 429 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index ec7703565..5039c26aa 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.03 18:56}
+\newcontextversion{2020.12.04 20:19}
%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 8ffceb405..8b103d931 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.03 18:56}
+\edef\contextversion{2020.12.04 20:19}
%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 9483292ec..e77e90e59 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.03 18:56}
+\newcontextversion{2020.12.04 20:19}
%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 0ae1b5027..fd88f9914 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.03 18:56}
+\edef\contextversion{2020.12.04 20:19}
%D Kind of special:
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index b6aed6495..22286e42d 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 29161ec70..844a0c16e 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
deleted file mode 100644
index 78fc22964..000000000
--- a/tex/context/base/mkiv/typo-spa.lua
+++ /dev/null
@@ -1,246 +0,0 @@
-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-out.lmt b/tex/context/base/mkxl/back-out.lmt
index 43fc04d78..fbcb220dc 100644
--- a/tex/context/base/mkxl/back-out.lmt
+++ b/tex/context/base/mkxl/back-out.lmt
@@ -228,6 +228,8 @@ function nodepool.literal(mode,str)
return t
end
+--- these 3 will move to node-res as they are generic
+
function nodepool.save()
return copynode(savenode)
end
@@ -238,7 +240,7 @@ end
function nodepool.setmatrix(rx,sx,sy,ry,tx,ty)
local t = copynode(setmatrixnode)
- nodeproperties[t] = { rx, sx, sy, ry, tx, ty }
+ nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } }
return t
end
diff --git a/tex/context/base/mkxl/back-trf.lmt b/tex/context/base/mkxl/back-trf.lmt
index 1586bc440..e3ec0bda3 100644
--- a/tex/context/base/mkxl/back-trf.lmt
+++ b/tex/context/base/mkxl/back-trf.lmt
@@ -32,10 +32,10 @@ local stack = { }
local restore = true -- false
updaters.register("backend.update",function()
- savenode = nodepool.save
- restorenode = nodepool.restore
- setmatrixnode = nodepool.setmatrix
- literalnode = nodepool.literal -- has to become some nodeinjection
+ savenode = nodepool.save -- not needed
+ restorenode = nodepool.restore -- not needed
+ setmatrixnode = nodepool.setmatrix -- not needed
+ literalnode = nodepool.literal -- has to become some nodeinjection
end)
local function stopsomething()
diff --git a/tex/context/base/mkxl/cont-log.mkxl b/tex/context/base/mkxl/cont-log.mkxl
index 12d0d06de..1bb48f0b2 100644
--- a/tex/context/base/mkxl/cont-log.mkxl
+++ b/tex/context/base/mkxl/cont-log.mkxl
@@ -194,7 +194,7 @@
\frozen\instance\protected\def\Lua {Lua}
\frozen\instance\protected\def\luajitTeX {lua\wordboundary jit\wordboundary\TeX}
\frozen\instance\protected\def\luametaTeX{lua\wordboundary meta\wordboundary\TeX}
-%frozen\instance\protected\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX}
+\frozen\instance\protected\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX}
% Adapted from a patch by Mojca:
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index 12ac9bafd..f56aaae6a 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.03 18:56}
+\newcontextversion{2020.12.04 20:19}
%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 1320962e7..40fca9fd9 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.03 18:56}
+\immutable\edef\contextversion{2020.12.04 20:19}
%overloadmode 1 % check frozen / warning
%overloadmode 2 % check frozen / error
diff --git a/tex/context/base/mkxl/grph-inc.mkxl b/tex/context/base/mkxl/grph-inc.mkxl
index 024db290e..4a6626617 100644
--- a/tex/context/base/mkxl/grph-inc.mkxl
+++ b/tex/context/base/mkxl/grph-inc.mkxl
@@ -178,12 +178,6 @@
\installcorenamespace{externalfiguredefinition}
-% \protected\def\defineexternalfigure
-% {\dodoubleargument\grph_include_define}
-%
-% \def\grph_include_define[#1][#2]%
-% {\setvalue{\??externalfiguredefinition#1}{\setupcurrentexternalfigure[#2]}}
-
\aliased\let\defineexternalfigures\defineexternalfigure
% label file parent settings
diff --git a/tex/context/base/mkxl/lpdf-lmt.lmt b/tex/context/base/mkxl/lpdf-lmt.lmt
index 1cbe033a3..cbad20f09 100644
--- a/tex/context/base/mkxl/lpdf-lmt.lmt
+++ b/tex/context/base/mkxl/lpdf-lmt.lmt
@@ -812,12 +812,9 @@ local flushsave, flushrestore, flushsetmatrix do
flushsetmatrix = function(current,pos_h,pos_v)
local p = nodeproperties[current]
if p then
- local m = matrix
+ local m = p.matrix
if m then
- local rx = m.rx
- local sx = m.sx
- local sy = m.sy
- local ry = m.ry
+ local rx, sx, sy, ry = unpack(m)
if not rx then
rx = 1
elseif rx == 0 then
diff --git a/tex/context/base/mkxl/lpdf-tag.lmt b/tex/context/base/mkxl/lpdf-tag.lmt
index 5cc2f5012..4ea92d951 100644
--- a/tex/context/base/mkxl/lpdf-tag.lmt
+++ b/tex/context/base/mkxl/lpdf-tag.lmt
@@ -425,6 +425,9 @@ end
collectranges(head)
+-- inspect(taglist)
+-- inspect(ranges)
+
if trace_tags then
for i=1,#ranges do
local range = ranges[i]
diff --git a/tex/context/base/mkxl/meta-ini.mkxl b/tex/context/base/mkxl/meta-ini.mkxl
index 4bf9134f9..fbbf95fc8 100644
--- a/tex/context/base/mkxl/meta-ini.mkxl
+++ b/tex/context/base/mkxl/meta-ini.mkxl
@@ -739,7 +739,7 @@
\meta_enable_include % redundant
\global\advance\c_meta_object_counter\plusone
\meta_use_box{\number\c_meta_object_counter}\hpack{\meta_process_graphic{#3}}% was vbox, graphic must end up as hbox
- \gdefcsname\??mpgraphic#1\endcsname{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}%
+ \xdefcsname\??mpgraphic#1\endcsname{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}%
\csname\??mpgraphic#1\endcsname\empty
\endgroup}
diff --git a/tex/context/base/mkxl/node-nut.lmt b/tex/context/base/mkxl/node-nut.lmt
index 6b9dd803e..38ac5b0aa 100644
--- a/tex/context/base/mkxl/node-nut.lmt
+++ b/tex/context/base/mkxl/node-nut.lmt
@@ -217,6 +217,7 @@ local nuts = {
unprotect_glyph = direct.unprotect_glyph,
unprotect_glyphs = direct.unprotect_glyphs,
unset_attribute = direct.unset_attribute,
+ unset_attributes = direct.unset_attributes,
usedlist = direct.usedlist,
uses_font = direct.uses_font,
vpack = direct.vpack,
diff --git a/tex/context/base/mkxl/page-bck.mkxl b/tex/context/base/mkxl/page-bck.mkxl
index 71036e3e4..5bdeb53fa 100644
--- a/tex/context/base/mkxl/page-bck.mkxl
+++ b/tex/context/base/mkxl/page-bck.mkxl
@@ -518,7 +518,7 @@
\processcommacommand[#1]\page_backgrounds_setup_step
\the\everybackgroundssetup}
-\protected\def\page_backgrounds_setup_single[#1][#2][#3]%
+\protected\def\page_backgrounds_setup_single[#1][#2][#-]%
{\global\settrue\c_page_backgrounds_some
\doifelsecommon{#1}\v_page_backgrounds_single_set
{\def\page_backgrounds_setup_step##1{\page_backgrounds_setup_and_check{##1}{#2}}%
@@ -526,7 +526,7 @@
\the\everybackgroundssetup}%
{\page_backgrounds_setup_double[#1][\v_page_backgrounds_common_set][#2]}}
-\protected\def\page_backgrounds_setup_basics[#1][#2][#3]%
+\protected\def\page_backgrounds_setup_basics[#1][#-][#-]%
{\setupframed[\??layoutbackgrounds][#1]%
\the\everybackgroundssetup}
diff --git a/tex/context/base/mkxl/syst-ini.mkxl b/tex/context/base/mkxl/syst-ini.mkxl
index 5e9d55559..57cd20759 100644
--- a/tex/context/base/mkxl/syst-ini.mkxl
+++ b/tex/context/base/mkxl/syst-ini.mkxl
@@ -138,14 +138,9 @@
%D available; it cannot limit itself to being \TEX\ or \ETEX. It could not do that
%D anyway because there are differences (no backend, to mention one).
-%D Temp hack ... build bot down:
-
-%D We create (for now) aliases:
-
\directlua {
- local primitives = tex.extraprimitives() % "tex","etex","luatex"
- tex.enableprimitives("normal",primitives) % could default to everything
- function tex.enableprimitives() end % so we kind of protect what's there
+ tex.enableprimitives("normal",true) % we default to everything
+ function tex.enableprimitives() end % so we kind of protect what's there
}
\immutable\def\space{ }
diff --git a/tex/context/base/mkxl/tabl-tbl.mkxl b/tex/context/base/mkxl/tabl-tbl.mkxl
index d46eebe6a..a4e6e6fed 100644
--- a/tex/context/base/mkxl/tabl-tbl.mkxl
+++ b/tex/context/base/mkxl/tabl-tbl.mkxl
@@ -712,7 +712,7 @@
% \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth
% \fi
% \tabl_tabulate_set_preamble}
-%
+
\def\tabl_tabulate_set_raggedright {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedright \fi}
\def\tabl_tabulate_set_raggedcenter{\ifnum\c_tabl_tabulate_type=\plusone \else\raggedcenter\fi}
\def\tabl_tabulate_set_raggedleft {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedleft \fi}
@@ -1071,7 +1071,8 @@
\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
{\ifcsname\??tabulatehead\currenttabulation\endcsname
%\expandafter\ifempty\csname\??tabulatehead\currenttabulation\endcsname
- \expandafter\ifempty\lastnamedcs
+ %\expandafter\ifempty\lastnamedcs
+ \ifempty\lastnamedcs
\let\tabl_tabulate_insert_head\empty
\else
\let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
@@ -1080,8 +1081,9 @@
\let\tabl_tabulate_insert_head\empty
\fi
\ifcsname\??tabulatefoot\currenttabulation\endcsname
- \expandafter\ifempty\csname\??tabulatefoot\currenttabulation\endcsname
+ %\expandafter\ifempty\csname\??tabulatefoot\currenttabulation\endcsname
%\expandafter\ifempty\lastnamedcs
+ \ifempty\lastnamedcs
\let\tabl_tabulate_insert_foot\empty
\else
\let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content
diff --git a/tex/context/base/mkxl/typo-brk.lmt b/tex/context/base/mkxl/typo-brk.lmt
new file mode 100644
index 000000000..8d2fcd147
--- /dev/null
+++ b/tex/context/base/mkxl/typo-brk.lmt
@@ -0,0 +1,498 @@
+if not modules then modules = { } end modules ['typo-brk'] = {
+ version = 1.001,
+ comment = "companion to typo-brk.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code dates from the beginning and is kind of experimental; it
+-- will be optimized and improved soon
+
+local next, type, tonumber, tostring = next, type, tonumber, tostring
+local utfbyte, utfchar = utf.byte, utf.char
+local format = string.format
+
+local trace_breakpoints = false trackers.register("typesetters.breakpoints", function(v) trace_breakpoints = v end)
+
+local report_breakpoints = logs.reporter("typesetting","breakpoints")
+
+local nodes, node = nodes, node
+
+local settings_to_array = utilities.parsers.settings_to_array
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getboth = nuts.getboth
+local getsubtype = nuts.getsubtype
+local getfont = nuts.getfont
+local getid = nuts.getid
+local getattrlist = nuts.getattrlist
+local getattr = nuts.getattr
+local getlanguage = nuts.getlanguage
+local isglyph = nuts.isglyph
+
+local setattr = nuts.setattr
+local setattrlist = nuts.setattrlist
+local setlink = nuts.setlink
+local setchar = nuts.setchar
+local setdisc = nuts.setdisc
+local setnext = nuts.setnext
+local setprev = nuts.setprev
+local setboth = nuts.setboth
+local setsubtype = nuts.setsubtype
+
+local copy_node = nuts.copy_node
+local copy_node_list = nuts.copy_list
+local flush_node = nuts.flush_node
+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 find_attribute = nuts.find_attribute
+local unset_attributes = nuts.unset_attributes
+
+local tonodes = nuts.tonodes
+
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
+
+local nodepool = nuts.pool
+local enableaction = nodes.tasks.enableaction
+
+local v_reset = interfaces.variables.reset
+local v_yes = interfaces.variables.yes
+
+local implement = interfaces.implement
+
+local new_penalty = nodepool.penalty
+local new_glue = nodepool.glue
+local new_disc = nodepool.disc
+local new_wordboundary = nodepool.wordboundary
+
+local nodecodes = nodes.nodecodes
+local kerncodes = nodes.kerncodes
+
+local kern_code = nodecodes.kern
+local math_code = nodecodes.math
+
+local fontkern_code = kerncodes.fontkern
+local italickern_code = kerncodes.italiccorrection
+
+local is_letter = characters.is_letter
+
+local typesetters = typesetters
+
+typesetters.breakpoints = typesetters.breakpoints or {}
+local breakpoints = typesetters.breakpoints
+
+breakpoints.mapping = breakpoints.mapping or { }
+breakpoints.numbers = breakpoints.numbers or { }
+
+breakpoints.methods = breakpoints.methods or { }
+local methods = breakpoints.methods
+
+local a_breakpoints = attributes.private("breakpoint")
+
+storage.register("typesetters/breakpoints/mapping", breakpoints.mapping, "typesetters.breakpoints.mapping")
+
+local mapping = breakpoints.mapping
+local numbers = breakpoints.mapping
+
+for i=1,#mapping do
+ local m = mapping[i]
+ numbers[m.name] = m
+end
+
+-- this needs a cleanup ... maybe make all of them disc nodes
+
+-- todo: use boundaries
+
+local function insert_break(head,start,stop,before,after,kern)
+ if not kern then
+ local p = new_penalty(before)
+ local g = new_glue()
+ setattrlist(p,start)
+ setattrlist(g,start)
+ insert_node_before(head,start,p)
+ insert_node_before(head,start,g)
+ end
+ local p = new_penalty(after)
+ local g = new_glue()
+ setattrlist(p,start)
+ setattrlist(g,start)
+ insert_node_after(head,stop,g)
+ insert_node_after(head,stop,p)
+end
+
+methods[1] = function(head,start,stop,settings,kern)
+ local p, n = getboth(stop)
+ if p and n then
+ insert_break(head,start,stop,10000,0,kern)
+ end
+ return head, stop
+end
+
+methods[6] = function(head,start,stop,settings,kern)
+ local p = getprev(start)
+ local n = getnext(stop)
+ if p and n then
+ if kern then
+ insert_break(head,start,stop,10000,0,kern)
+ else
+ local l = new_wordboundary()
+ local d = new_disc()
+ local r = new_wordboundary()
+ setattrlist(d,start) -- otherwise basemode is forced and we crash
+ setlink(p,l,d,r,n)
+ if start == stop then
+ setboth(start)
+ setdisc(d,start,nil,copy_node(start))
+ else
+ setprev(start)
+ setnext(stop)
+ setdisc(d,start,nil,copy_node_list(start))
+ end
+ stop = r
+ end
+ end
+ return head, stop
+end
+
+methods[2] = function(head,start) -- ( => (-
+ local p, n = getboth(start)
+ if p and n then
+ local replace
+ head, start, replace = remove_node(head,start)
+ local post = copy_node(replace)
+ local hyphen = copy_node(post)
+ setchar(hyphen,languages.prehyphenchar(getlanguage(post)))
+ setlink(post,hyphen)
+ head, start = insert_node_before(head,start,new_disc(nil,post,replace))
+ setattrlist(start,replace)
+ insert_break(head,start,start,10000,10000)
+ end
+ return head, start
+end
+
+methods[3] = function(head,start) -- ) => -)
+ local p, n = getboth(start)
+ if p and n then
+ local replace
+ head, start, replace = remove_node(head,start)
+ local pre = copy_node(replace)
+ local hyphen = copy_node(pre)
+ setchar(hyphen,languages.prehyphenchar(getlanguage(pre)))
+ setlink(hyphen,pre)
+ head, start = insert_node_before(head,start,new_disc(hyphen,nil,replace)) -- so not pre !
+ setattrlist(start,tmp)
+ insert_break(head,start,start,10000,10000)
+ end
+ return head, start
+end
+
+methods[4] = function(head,start) -- - => - - -
+ local p, n = getboth(start)
+ if p and n then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,new_disc())
+ setattrlist(start,tmp)
+ setdisc(start,copy_node(tmp),copy_node(tmp),tmp)
+ insert_break(head,start,start,10000,10000)
+ end
+ return head, start
+end
+
+methods[5] = function(head,start,stop,settings) -- x => p q r
+ local p, n = getboth(start)
+ if p and n then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,new_disc())
+ local attr = getattrlist(tmp)
+ local font = getfont(tmp)
+ local left = settings.left
+ local right = settings.right
+ local middle = settings.middle
+ if left then
+ left = tonodes(tostring(left),font,attr)
+ end
+ if right then
+ right = tonodes(tostring(right),font,attr)
+ end
+ if middle then
+ middle = tonodes(tostring(middle),font,attr)
+ end
+ setdisc(start,left,right,middle)
+ setattrlist(start,attr)
+ flush_node(tmp)
+ insert_break(head,start,start,10000,10000)
+ end
+ return head, start
+end
+
+-- we know we have a limited set
+-- what if characters are replaced by the font handler
+-- do we need to go into disc nodes (or do it as first step but then we need a pre/post font handler)
+
+function breakpoints.handler(head)
+ local _, current = find_attribute(head, a_breakpoints)
+ if current then
+ local done = false
+ local attr = nil
+ local map = nil
+ local current = head
+ while current do
+ local char, id = isglyph(current)
+ if char then
+ local a = getattr(current,a_breakpoints)
+ if a and a > 0 then
+ if a ~= attr then
+ local data = mapping[a]
+ if data then
+ map = data.characters
+ else
+ map = nil
+ end
+ attr = a
+ end
+ if map then
+ local cmap = map[char]
+ if cmap then
+ -- for now we collect but when found ok we can move the handler here
+ -- although it saves nothing in terms of performance
+ local lang = getlanguage(current)
+ local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[languages.numbers[lang]] or cmap[""])
+ if smap then
+ local skip = smap.skip
+ local start = current
+ local stop = current
+ current = getnext(current)
+ if skip then
+ while current do
+ local c = isglyph(current)
+ if c == char then
+ stop = current
+ current = getnext(current)
+ else
+ break
+ end
+ end
+ end
+ local d = { start, stop, cmap, smap, char }
+ if done then
+ done[#done+1] = d
+ else
+ done = { d }
+ end
+ else
+ current = getnext(current)
+ end
+ else
+ current = getnext(current)
+ end
+ else
+ current = getnext(current)
+ end
+ else
+ current = getnext(current)
+ end
+ elseif id == math_code then
+ attr = nil
+ current = end_of_math(current)
+ if current then
+ current = getnext(current)
+ end
+ else
+ current = getnext(current)
+ end
+ end
+ if not done then
+ return head
+ end
+ -- we have hits
+ -- local numbers = languages.numbers
+ for i=1,#done do
+ local data = done[i]
+ local start = data[1]
+ local stop = data[2]
+ local cmap = data[3]
+ local smap = data[4]
+ -- we do a sanity check for language
+ -- local lang = getlanguage(start)
+ -- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
+ -- if smap then
+ local nleft = smap.nleft
+ local cleft = 0
+ local prev = getprev(start)
+ local kern = nil
+ while prev and nleft ~= cleft do
+ local char, id = isglyph(prev)
+ if char then
+ if not is_letter[char] then
+ cleft = -1
+ break
+ end
+ cleft = cleft + 1
+ prev = getprev(prev)
+ elseif id == kern_code then
+ local s = getsubtype(prev)
+ if s == fontkern_code or s == italickern_code then
+ if cleft == 0 then
+ kern = prev
+ prev = getprev(prev)
+ else
+ break
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if nleft == cleft then
+ local nright = smap.nright
+ local cright = 0
+ local next = getnext(stop) -- getnext(start)
+ while next and nright ~= cright do
+ local char, id = isglyph(next)
+ if char then
+ if not is_letter[char] then
+ cright = -1
+ break
+ end
+ if cright == 1 and cmap[char] then
+ -- let's not make it too messy
+ break
+ end
+ cright = cright + 1
+ next = getnext(next)
+ elseif id == kern_code then
+ local s = getsubtype(next)
+ if s == fontkern_code or s == italickern_code then
+ if cleft == 0 then
+ next = getnext(next)
+ else
+ break
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if nright == cright then
+ local method = methods[smap.type]
+ if method then
+ head, start = method(head,start,stop,smap,kern)
+ end
+ end
+ -- end
+ end
+ end
+ if done then
+-- unset_attributes(a_breakpoints, head)
+ end
+ end
+ return head
+end
+
+local enabled = false
+
+function breakpoints.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 breakpoints.setreplacement(name,char,language,settings)
+ char = utfbyte(char)
+ local data = numbers[name]
+ if data then
+ local characters = data.characters
+ local cmap = characters[char]
+ if not cmap then
+ cmap = { }
+ characters[char] = cmap
+ end
+ local left, right, middle = settings.left, settings.right, settings.middle
+ cmap[language or ""] = {
+ type = tonumber(settings.type) or 1,
+ nleft = tonumber(settings.nleft) or 1,
+ nright = tonumber(settings.nright) or 1,
+ left = left ~= "" and left or nil,
+ right = right ~= "" and right or nil,
+ middle = middle ~= "" and middle or nil,
+ skip = settings.range == v_yes,
+ } -- was { type or 1, before or 1, after or 1 }
+ end
+end
+
+function breakpoints.set(n)
+ if n == v_reset then
+ n = unsetvalue
+ else
+ n = mapping[n]
+ if not n then
+ n = unsetvalue
+ else
+ if not enabled then
+ if trace_breakpoints then
+ report_breakpoints("enabling breakpoints handler")
+ end
+ enableaction("processors","typesetters.breakpoints.handler")
+ end
+ n = n.number
+ end
+ end
+ texsetattribute(a_breakpoints,n)
+end
+
+-- interface
+
+implement {
+ name = "definebreakpoints",
+ actions = breakpoints.define,
+ arguments = "string"
+}
+
+implement {
+ name = "definebreakpoint",
+ actions = breakpoints.setreplacement,
+ arguments = {
+ "string",
+ "string",
+ "string",
+ {
+ { "type", "integer" },
+ { "nleft", "integer" },
+ { "nright", "integer" },
+ { "right" },
+ { "left" },
+ { "middle" },
+ { "range" },
+ }
+ }
+}
+
+implement {
+ name = "setbreakpoints",
+ actions = breakpoints.set,
+ arguments = "string"
+}
diff --git a/tex/context/base/mkxl/typo-brk.mkxl b/tex/context/base/mkxl/typo-brk.mkxl
index 51abc1034..47e5da886 100644
--- a/tex/context/base/mkxl/typo-brk.mkxl
+++ b/tex/context/base/mkxl/typo-brk.mkxl
@@ -21,7 +21,7 @@
%
% -- we might eventually stick to only method 5
-\registerctxluafile{typo-brk}{}
+\registerctxluafile{typo-brk}{autosuffix}
\definesystemattribute[breakpoint][public,global]
diff --git a/tex/context/base/mkxl/typo-cap.lmt b/tex/context/base/mkxl/typo-cap.lmt
index c5c91243e..fe7406e76 100644
--- a/tex/context/base/mkxl/typo-cap.lmt
+++ b/tex/context/base/mkxl/typo-cap.lmt
@@ -19,83 +19,85 @@ local report_casing = logs.reporter("typesetting","casing")
local nodes, node = nodes, node
-local nuts = nodes.nuts
+local nuts = nodes.nuts
-local getnext = nuts.getnext
-local getid = nuts.getid
-local takeattr = nuts.takeattr
-local getfont = nuts.getfont
-local getsubtype = nuts.getsubtype
-local getchar = nuts.getchar
-local isglyph = nuts.isglyph
-local getdisc = nuts.getdisc
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local isglyph = nuts.isglyph
+local getdisc = nuts.getdisc
-local setchar = nuts.setchar
-local setfont = nuts.setfont
+local setchar = nuts.setchar
+local setfont = nuts.setfont
-local copy_node = nuts.copy
-local end_of_math = nuts.end_of_math
-local insert_after = nuts.insert_after
-local find_attribute = nuts.find_attribute
+local copy_node = nuts.copy
+local end_of_math = nuts.end_of_math
+local insert_after = nuts.insert_after
+local find_attribute = nuts.find_attribute
+local unset_attributes = nuts.unset_attributes
-local nextglyph = nuts.traversers.glyph
+local nextglyph = nuts.traversers.glyph
-local nodecodes = nodes.nodecodes
-local kerncodes = nodes.kerncodes
+local nodecodes = nodes.nodecodes
+local kerncodes = nodes.kerncodes
-local glyph_code = nodecodes.glyph
-local kern_code = nodecodes.kern
-local disc_code = nodecodes.disc
-local math_code = nodecodes.math
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
+local disc_code = nodecodes.disc
+local math_code = nodecodes.math
-local fontkern_code = kerncodes.fontkern
+local fontkern_code = kerncodes.fontkern
-local enableaction = nodes.tasks.enableaction
+local enableaction = nodes.tasks.enableaction
-local newkern = nuts.pool.kern
+local newkern = nuts.pool.kern
-local fonthashes = fonts.hashes
-local fontdata = fonthashes.identifiers
-local fontchar = fonthashes.characters
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local fontchar = fonthashes.characters
-local currentfont = font.current
+local currentfont = font.current
-local variables = interfaces.variables
-local v_reset = variables.reset
+local variables = interfaces.variables
+local v_reset = variables.reset
-local texsetattribute = tex.setattribute
-local unsetvalue = attributes.unsetvalue
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
-typesetters = typesetters or { }
-local typesetters = typesetters
+typesetters = typesetters or { }
+local typesetters = typesetters
-typesetters.cases = typesetters.cases or { }
-local cases = typesetters.cases
+typesetters.cases = typesetters.cases or { }
+local cases = typesetters.cases
-cases.actions = { }
-local actions = cases.actions
-local a_cases = attributes.private("case")
+cases.actions = { }
+local actions = cases.actions
+local a_cases = attributes.private("case")
-local extract = bit32.extract
-local run = 0 -- a trick to make neighbouring ranges work
-local blocked = { }
+local run = 0 -- a trick to make neighbouring ranges work
+local blocked = { }
local function set(tag,font)
- if run == 0x40 then -- 2^6
- run = 1
- else
+ if run < 0x7F then
run = run + 1
+ else
+ run = 1
end
- local a = font * 0x10000 + tag * 0x100 + run
+ local a = (font << 16)
+ + (tag << 8)
+ + (run << 0)
blocked[a] = false
return a
end
local function get(a)
return
- extract(a, 8, 8), -- tag
- extract(a,16,12), -- font
- extract(a, 0, 8) -- run
+ (a >> 8) & 0x00FF, -- tag
+ (a >> 16) & 0xFFFF, -- font
+ (a >> 0) & 0x00FF -- run
end
-- a previous implementation used char(0) as placeholder for the larger font, so we needed
@@ -279,106 +281,103 @@ register(variables.camel, camel) -- 10
register(variables.cap, variables.capital) -- clone
register(variables.Cap, variables.Capital) -- clone
--- This can be more clever: when we unset we can actually use the same attr ref if
--- needed. Using properties to block further usage is not faster.
-
-function cases.handler(head) -- not real fast but also not used on much data
- local start = head
- local lastfont = { }
- local lastattr = nil
- local count = 0
- local previd = nil
- local prev = nil
- while start do -- while because start can jump ahead
- local id = getid(start)
- if id == glyph_code then
- local attr = takeattr(start,a_cases)
- if attr and attr > 0 and not blocked[attr] then
- if attr ~= lastattr then
- lastattr = attr
- count = 1
- else
- count = count + 1
- end
- local n, id, m = get(attr)
- if lastfont[n] == nil then
- lastfont[n] = id
- end
- local action = actions[n] -- map back to low number
- if action then
- local quit
- start, quit = action(start,attr,lastfont,n,count)
- if trace_casing then
- report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,quit and "-" or "+")
+function cases.handler(head)
+ local _, start = find_attribute(head, a_cases)
+ if start then
+ local lastfont = { }
+ local lastattr = nil
+ local count = 0
+ local done = false
+ while start do -- while because start can jump ahead
+ local id = getid(start)
+ if id == glyph_code then
+ local attr = getattr(start,a_cases)
+ if attr and attr > 0 and not blocked[attr] then
+ if attr ~= lastattr then
+ lastattr = attr
+ count = 1
+ else
+ count = count + 1
end
- elseif trace_casing then
- report_casing("unknown case trigger %a",n)
- end
- end
- elseif id == disc_code then
- local attr = takeattr(start,a_cases)
- if attr and attr > 0 and not blocked[attr] then
- if attr ~= lastattr then
- lastattr = attr
- count = 0
- end
- local n, id, m = get(attr)
- if lastfont[n] == nil then
- lastfont[n] = id
+ local n, id, m = get(attr)
+ if lastfont[n] == nil then
+ lastfont[n] = id
+ end
+ local action = actions[n] -- map back to low number
+ if action then
+ local quit
+ start, quit = action(start,attr,lastfont,n,count)
+ if trace_casing then
+ report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,quit and "-" or "+")
+ end
+ elseif trace_casing then
+ report_casing("unknown case trigger %a",n)
+ end
+ done = true
end
- local action = actions[n] -- map back to low number
- if action then
- local pre, post, replace = getdisc(start)
- if replace then
- local cnt = count
- for g in nextglyph, replace do
- cnt = cnt + 1
- takeattr(g,a_cases)
- local h, quit = action(start,attr,lastfont,n,cnt,"replace",g)
- if quit then
- break
+ elseif id == disc_code then
+ local attr = getattr(start,a_cases)
+ if attr and attr > 0 and not blocked[attr] then
+ if attr ~= lastattr then
+ lastattr = attr
+ count = 0
+ end
+ local n, id, m = get(attr)
+ if lastfont[n] == nil then
+ lastfont[n] = id
+ end
+ local action = actions[n] -- map back to low number
+ if action then
+ local pre, post, replace = getdisc(start)
+ if replace then
+ local cnt = count
+ for g in nextglyph, replace do
+ cnt = cnt + 1
+ getattr(g,a_cases)
+ local h, quit = action(start,attr,lastfont,n,cnt,"replace",g)
+ if quit then
+ break
+ end
end
end
- end
- if pre then
- local cnt = count
- for g in nextglyph, pre do
- cnt = cnt + 1
- takeattr(g,a_cases)
- local h, quit = action(start,attr,lastfont,n,cnt,"pre",g)
- if quit then
- break
+ if pre then
+ local cnt = count
+ for g in nextglyph, pre do
+ cnt = cnt + 1
+ getattr(g,a_cases)
+ local h, quit = action(start,attr,lastfont,n,cnt,"pre",g)
+ if quit then
+ break
+ end
end
end
- end
- if post then
- local cnt = count
- for g in nextglyph, post do
- cnt = cnt + 1
- takeattr(g,a_cases)
- local h, quit = action(start,attr,lastfont,n,cnt,"post",g)
- if quit then
- break
+ if post then
+ local cnt = count
+ for g in nextglyph, post do
+ cnt = cnt + 1
+ getattr(g,a_cases)
+ local h, quit = action(start,attr,lastfont,n,cnt,"post",g)
+ if quit then
+ break
+ end
end
end
end
+ count = count + 1
+ done = true
end
- count = count + 1
- end
- elseif id == math_code then
- start = end_of_math(start)
- count = 0
- elseif count > 0 then
- if prev_id == kern_code and getsubtype(prev) == fontkern_code then
- -- still inside a word ...normally kerns are added later
else
+ if id == math_code then
+ start = end_of_math(start)
+ end
count = 0
end
+ if start then
+ start = getnext(start)
+ end
end
- if start then
- prev = start
- previd = id
- start = getnext(start)
+ if done then
+ -- unset_attributes(a_cases,head)
end
end
return head
@@ -415,6 +414,5 @@ interfaces.implement {
-- public = true,
-- protected = true,
actions = cases.set,
--- arguments = { "string" }
arguments = { "argument" }
}
diff --git a/tex/context/base/mkxl/typo-cap.mkxl b/tex/context/base/mkxl/typo-cap.mkxl
index 8c0cab502..86f3647dc 100644
--- a/tex/context/base/mkxl/typo-cap.mkxl
+++ b/tex/context/base/mkxl/typo-cap.mkxl
@@ -18,7 +18,8 @@
%D Maybe we need a more clever system: either command or style mode etc. so
%D that we can avoid the grouped mess in a simple style switch.
-\registerctxluafile{typo-cap}{autosuffix,optimize}
+% \registerctxluafile{typo-cap}{autosuffix,optimize}
+\registerctxluafile{typo-cap}{autosuffix}
% \definesystemattribute[case][public] % already predefined
diff --git a/tex/context/base/mkxl/typo-dig.lmt b/tex/context/base/mkxl/typo-dig.lmt
new file mode 100644
index 000000000..7f6663db9
--- /dev/null
+++ b/tex/context/base/mkxl/typo-dig.lmt
@@ -0,0 +1,181 @@
+if not modules then modules = { } end modules ['typo-dig'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to typo-dig.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- we might consider doing this after the otf pass because now osf do not work
+-- out well in node mode.
+
+local next, type, tonumber = next, type, tonumber
+local format, insert = string.format, table.insert
+local round, div = math.round, math.div
+
+local trace_digits = false trackers.register("typesetters.digits", function(v) trace_digits = v end)
+
+local report_digits = logs.reporter("typesetting","digits")
+
+local nodes, node = nodes, node
+
+local nuts = nodes.nuts
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getwidth = nuts.getwidth
+local isglyph = nuts.isglyph
+local getattr = nuts.getattr
+
+local setlink = nuts.setlink
+local setnext = nuts.setnext
+local setprev = nuts.setprev
+
+local hpack_node = nuts.hpack
+local traverse_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local find_attribute = nuts.find_attribute
+local unset_attributes = nuts.unset_attributes
+
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+
+local nodepool = nuts.pool
+local enableaction = nodes.tasks.enableaction
+
+local new_glue = nodepool.glue
+
+local fonthashes = fonts.hashes
+local chardata = fonthashes.characters
+
+local v_reset = interfaces.variables.reset
+
+local charbase = characters.data
+local getdigitwidth = fonts.helpers.getdigitwidth
+
+typesetters = typesetters or { }
+local typesetters = typesetters
+
+typesetters.digits = typesetters.digits or { }
+local digits = typesetters.digits
+
+digits.actions = { }
+local actions = digits.actions
+
+local a_digits = attributes.private("digits")
+
+-- at some point we can manipulate the glyph node so then i need
+-- to rewrite this then
+
+function nodes.aligned(head,start,stop,width,how)
+ if how == "flushright" or how == "middle" then
+ head, start = insert_node_before(head,start,new_glue(0,65536,65536))
+ end
+ if how == "flushleft" or how == "middle" then
+ head, stop = insert_node_after(head,stop,new_glue(0,65536,65536))
+ end
+ local prv = getprev(start)
+ local nxt = getnext(stop)
+ setprev(start)
+ setnext(stop)
+ local packed = hpack_node(start,width,"exactly") -- no directional mess here, just lr
+ if prv then
+ setlink(prv,packed)
+ end
+ if nxt then
+ setlink(packed,nxt)
+ end
+ if getprev(packed) then
+ return head, packed
+ else
+ return packed, packed
+ end
+end
+
+actions[1] = function(head,start,attr)
+ local char, font = isglyph(start)
+ local unic = chardata[font][char].unicode or char
+ if charbase[unic].category == "nd" then -- ignore unic tables
+ local oldwidth = getwidth(start)
+ local newwidth = getdigitwidth(font)
+ if newwidth ~= oldwidth then
+ if trace_digits then
+ report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s",
+ attr%100,div(attr,100),char,unic,newwidth-oldwidth)
+ end
+ head, start = nodes.aligned(head,start,start,newwidth,"middle")
+ return head, start
+ end
+ end
+ return head, start
+end
+
+function digits.handler(head)
+ local _, start = find_attribute(head, a_digits)
+ if start then
+ local current = head
+ while current do
+ if getid(current) == glyph_code then
+ local attr = getattr(current,a_digits)
+ if attr and attr > 0 then
+ local action = actions[attr%100] -- map back to low number
+ if action then
+ head, current = action(head,current,attr)
+ elseif trace_digits then
+ report_digits("unknown digit trigger %a",attr)
+ end
+ done = true
+ end
+ end
+ if current then
+ current = getnext(current)
+ end
+ end
+ if done then
+ unset_attributes(a_digits, head)
+ end
+ end
+ return head
+end
+
+local m, enabled = 0, false -- a trick to make neighbouring ranges work
+
+function digits.set(n) -- number or 'reset'
+ if n == v_reset then
+ n = unsetvalue
+ else
+ n = tonumber(n)
+ if n then
+ if not enabled then
+ enableaction("processors","typesetters.digits.handler")
+ if trace_digits then
+ report_digits("enabling digit handler")
+ end
+ enabled = true
+ end
+ if m == 100 then
+ m = 1
+ else
+ m = m + 1
+ end
+ n = m * 100 + n
+ else
+ n = unsetvalue
+ end
+ end
+ texsetattribute(a_digits,n)
+end
+
+-- interface
+
+interfaces.implement {
+ name = "setdigitsmanipulation",
+ actions = digits.set,
+ arguments = "string"
+}
diff --git a/tex/context/base/mkxl/typo-dig.mkxl b/tex/context/base/mkxl/typo-dig.mkxl
index 822fa0d34..308ccb66e 100644
--- a/tex/context/base/mkxl/typo-dig.mkxl
+++ b/tex/context/base/mkxl/typo-dig.mkxl
@@ -15,7 +15,7 @@
\unprotect
-\registerctxluafile{typo-dig}{}
+\registerctxluafile{typo-dig}{autosuffix}
\definesystemattribute[digits][public]
diff --git a/tex/context/base/mkxl/typo-krn.lmt b/tex/context/base/mkxl/typo-krn.lmt
new file mode 100644
index 000000000..a8ccedccf
--- /dev/null
+++ b/tex/context/base/mkxl/typo-krn.lmt
@@ -0,0 +1,630 @@
+if not modules then modules = { } end modules ['typo-krn'] = {
+ version = 1.001,
+ comment = "companion to typo-krn.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- glue is still somewhat suboptimal
+-- components: better split on tounicode
+--
+-- maybe ignore when properties[n].injections.cursivex (or mark)
+
+local next, type, tonumber = next, type, tonumber
+
+local nodes = nodes
+local fonts = fonts
+
+local enableaction = nodes.tasks.enableaction
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+-- check what is used
+
+local find_node_tail = nuts.tail
+local flush_node = nuts.flush_node
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local end_of_math = nuts.end_of_math
+local copy_node = nuts.copy
+local find_attribute = nuts.find_attribute
+local unset_attributes = nuts.unset_attributes
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getdisc = nuts.getdisc
+local getglue = nuts.getglue
+local getkern = nuts.getkern
+local getglyphdata = nuts.getglyphdata
+
+local isglyph = nuts.isglyph
+
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local setlink = nuts.setlink
+local setdisc = nuts.setdisc
+local setglue = nuts.setglue
+local setkern = nuts.setkern
+local setchar = nuts.setchar
+local setglue = nuts.setglue -- todo
+
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
+
+local new_kern = nodepool.kern
+local new_glue = nodepool.glue
+
+local nodecodes = nodes.nodecodes
+local kerncodes = nodes.kerncodes
+local gluecodes = nodes.gluecodes
+local disccodes = nodes.disccodes
+local listcodes = nodes.listcodes
+
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
+local disc_code = nodecodes.disc
+local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local math_code = nodecodes.math
+
+local boxlist_code = listcodes.box
+local unknownlist_code = listcodes.unknown
+
+local discretionarydisc_code = disccodes.discretionary
+local automaticdisc_code = disccodes.automatic
+
+local fontkern_code = kerncodes.fontkern
+local userkern_code = kerncodes.userkern
+
+local userskip_code = gluecodes.userskip
+local spaceskip_code = gluecodes.spaceskip
+local xspaceskip_code = gluecodes.xspaceskip
+
+local fonthashes = fonts.hashes
+local chardata = fonthashes.characters
+local quaddata = fonthashes.quads
+local markdata = fonthashes.marks
+local fontproperties = fonthashes.properties
+local fontdescriptions = fonthashes.descriptions
+local fontfeatures = fonthashes.features
+
+local tracers = nodes.tracers
+local setcolor = tracers.colors.set
+local resetcolor = tracers.colors.reset
+
+local v_max = interfaces.variables.max
+local v_auto = interfaces.variables.auto
+
+typesetters = typesetters or { }
+local typesetters = typesetters
+
+local kerns = typesetters.kerns or { }
+typesetters.kerns = kerns
+
+local report = logs.reporter("kerns")
+local trace_ligatures = false trackers.register("typesetters.kerns.ligatures", function(v) trace_ligatures = v end)
+local trace_ligatures_d = false trackers.register("typesetters.kerns.ligatures.details", function(v) trace_ligatures_d = v end)
+
+kerns.mapping = kerns.mapping or { }
+kerns.factors = kerns.factors or { }
+local a_kerns = attributes.private("kern")
+
+local contextsetups = fonts.specifiers.contextsetups
+
+storage.register("typesetters/kerns/mapping", kerns.mapping, "typesetters.kerns.mapping")
+storage.register("typesetters/kerns/factors", kerns.factors, "typesetters.kerns.factors")
+
+local mapping = kerns.mapping
+local factors = kerns.factors
+
+-- one must use liga=no and mode=base and kern=yes
+-- use more helpers
+-- make sure it runs after all others
+-- there will be a width adaptor field in nodes so this will change
+-- todo: interchar kerns / disc nodes / can be made faster
+-- todo: use insert_before etc
+
+local gluefactor = 4 -- assumes quad = .5 enspace
+
+-- red : kept by dynamic feature
+-- green : kept by static feature
+-- blue : keep by goodie
+
+function kerns.keepligature(n) -- might become default
+ local f = getfont(n)
+ local a = getglyphdata(n) or 0
+ if trace_ligatures then
+ local c = getchar(n)
+ local d = fontdescriptions[f][c].name
+ if a > 0 and contextsetups[a].keepligatures == v_auto then
+ if trace_ligatures_d then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","dynamic","keepligatures")
+ end
+ setcolor(n,"darkred")
+ return true
+ end
+ local k = fontfeatures[f].keepligatures
+ if k == v_auto then
+ if trace_ligatures_d then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","static","keepligatures")
+ end
+ setcolor(n,"darkgreen")
+ return true
+ end
+ if not k then
+ if trace_ligatures_d then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"split","static","keepligatures")
+ end
+ resetcolor(n)
+ return false
+ end
+ local k = fontproperties[f].keptligatures
+ if not k then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","no")
+ resetcolor(n)
+ return false
+ end
+ if k and k[c] then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"kept","by")
+ setcolor(n,"darkblue")
+ return true
+ else
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","by")
+ resetcolor(n)
+ return false
+ end
+ else
+ if a > 0 and contextsetups[a].keepligatures == v_auto then
+ return true
+ end
+ local k = fontfeatures[f].keepligatures
+ if k == v_auto then
+ return true
+ end
+ if not k then
+ return false
+ end
+ local k = fontproperties[f].keptligatures
+ if not k then
+ return false
+ end
+ if k and k[c] then
+ return true
+ end
+ end
+end
+
+-- can be optimized .. the prev thing .. but hardly worth the effort
+
+local function kern_injector(fillup,kern)
+ if fillup then
+ local g = new_glue(kern)
+ setfield(g,"stretch",kern)
+ setfield(g,"stretch_order",1)
+ return g
+ else
+ return new_kern(kern)
+ end
+end
+
+-- a simple list injector, no components and such .. just disable ligatures in
+-- kern mode .. maybe not even hyphenate ... anyway, the next one is for simple
+-- sublists .. beware: we can have char -1
+
+local function inject_begin(boundary,prev,keeptogether,krn,ok) -- prev is a glyph
+ local char, id = isglyph(boundary)
+ if id == kern_code then
+ if getsubtype(boundary) == fontkern_code then
+ local inject = true
+ if keeptogether then
+ local next = getnext(boundary)
+ if not next or (getid(next) == glyph_code and keeptogether(prev,next)) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setkern(boundary,getkern(boundary) + quaddata[getfont(prev)]*krn,userkern_code)
+ return boundary, true
+ end
+ end
+ elseif char then
+ if keeptogether and keeptogether(boundary,prev) then
+ -- keep 'm
+ else
+ local prevchar = isglyph(prev)
+ if prevchar and prevchar > 0 then
+ local font = getfont(boundary)
+ local data = chardata[font][prevchar]
+ local kerns = data and data.kerns
+ local kern = new_kern((kerns and kerns[char] or 0) + quaddata[font]*krn)
+ setlink(kern,boundary)
+ return kern, true
+ end
+ end
+ end
+ return boundary, ok
+end
+
+local function inject_end(boundary,next,keeptogether,krn,ok)
+ local tail = find_node_tail(boundary)
+ local char, id = isglyph(tail)
+ if id == kern_code then
+ if getsubtype(tail) == fontkern_code then
+ local inject = true
+ if keeptogether then
+ local prev = getprev(tail)
+ if getid(prev) == glyph_code and keeptogether(prev,two) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setkern(tail,getkern(tail) + quaddata[getfont(next)]*krn,userkern_code)
+ return boundary, true
+ end
+ end
+ elseif char then
+ if keeptogether and keeptogether(tail,two) then
+ -- keep 'm
+ else
+ local nextchar = isglyph(tail)
+ if nextchar and nextchar > 0 then
+ local font = getfont(tail)
+ local data = chardata[font][nextchar]
+ local kerns = data and data.kerns
+ local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn
+ setlink(tail,new_kern(kern))
+ return boundary, true
+ end
+ end
+ end
+ return boundary, ok
+end
+
+local function process_list(head,keeptogether,krn,font,okay)
+ local start = head
+ local prev = nil
+ local pid = nil
+ local kern = 0
+ local mark = font and markdata[font]
+ while start do
+ local char, id = isglyph(start)
+ if char then
+ if not font then
+ font = id -- getfont(start)
+ mark = markdata[font]
+ kern = quaddata[font]*krn
+ end
+ if prev then
+ if mark[char] then
+ -- skip
+ elseif pid == kern_code then
+ if getsubtype(prev) == fontkern_code then
+ local inject = true
+ if keeptogether then
+ local prevprev = getprev(prev)
+ if getid(prevprev) == glyph_code and keeptogether(prevprev,start) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setkern(prev,getkern(prev) + kern,userkern_code)
+ okay = true
+ end
+ end
+ elseif pid == glyph_code then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ local prevchar = getchar(prev)
+ local data = chardata[font][prevchar]
+ local kerns = data and data.kerns
+ -- if kerns then
+ -- print("it happens indeed, basemode kerns not yet injected")
+ -- end
+ insert_node_before(head,start,new_kern((kerns and kerns[char] or 0) + kern))
+ okay = true
+ end
+ end
+ end
+ end
+ if start then
+ prev = start
+ pid = id
+ start = getnext(start)
+ end
+ end
+ return head, okay, prev
+end
+
+local function closest_bound(b,get)
+ b = get(b)
+ if b and getid(b) ~= glue_code then
+ while b do
+ if not getattr(b,a_kerns) then
+ break
+ else
+ local c, f = isglyph(b)
+ if c then
+ return b, f
+ else
+ b = get(b)
+ end
+ end
+ end
+ end
+end
+
+function kerns.handler(head)
+ local _, start = find_attribute(head, a_kerns)
+ if start then
+ local lastfont = nil
+ local keepligature = kerns.keepligature
+ local keeptogether = kerns.keeptogether
+ local fillup = false
+ local bound = false
+ local prev = nil
+ local previd = nil
+ local prevchar = nil
+ local prevfont = nil
+ local prevmark = nil
+ local done = false
+ while start do
+ -- fontkerns don't get the attribute but they always sit between glyphs so
+ -- are always valid bound .. disc nodes also sometimes don't get them
+ local attr = getattr(start,a_kerns)
+ if attr and attr > 0 then
+ local char, id = isglyph(start)
+ local krn = mapping[attr]
+ if krn == v_max then
+ krn = .25
+ fillup = true
+ else
+ fillup = false
+ end
+ if not krn or krn == 0 then
+ bound = false
+ elseif char then -- id == glyph_code
+ local font = id -- more readable
+ local mark = markdata[font]
+ if keepligature and keepligature(start) then
+ -- keep 'm
+ else
+ -- beware, these are not kerned so we mighty need a kern only pass
+ -- maybe some day .. anyway, one should disable ligaturing
+ local data = chardata[font][char]
+ if data then
+ local unicode = data.unicode -- can be cached
+ if type(unicode) == "table" then
+ char = unicode[1]
+ local s = start
+ setchar(s,char)
+ for i=2,#unicode do
+ local n = copy_node(s)
+ if i == 2 then
+ setattr(n,a_kerns,attr) -- we took away the attr
+ end
+ setchar(n,unicode[i])
+ insert_node_after(head,s,n)
+ s = n
+ end
+ end
+ end
+ end
+ if not bound then
+ -- yet
+ elseif mark[char] then
+ -- skip
+ elseif previd == kern_code then
+ if getsubtype(prev) == fontkern_code then
+ local inject = true
+ if keeptogether then
+ if previd == glyph_code and keeptogether(prev,start) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setkern(prev,getkern(prev) + quaddata[font]*krn,userkern_code)
+ end
+ end
+ elseif previd == glyph_code then
+ if prevfont == font then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ -- hm, only basemode ... will go away ...
+ local data = chardata[font][prevchar]
+ local kerns = data and data.kerns
+ local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn
+ insert_node_before(head,start,kern_injector(fillup,kern))
+ end
+ else
+ insert_node_before(head,start,kern_injector(fillup,quaddata[font]*krn))
+ end
+ end
+ prev = start
+ prevchar = char
+ prevfont = font
+ prevmark = mark
+ previd = glyph_code -- id
+ bound = true
+ elseif id == disc_code then
+ local prev, next, pglyph, nglyph -- delayed till needed
+ local subtype = getsubtype(start)
+ -- if subtype == automaticdisc_code then
+ -- -- this is kind of special, as we have already injected the
+ -- -- previous kern
+ -- local prev = getprev(start)
+ -- local pglyph = prev and getid(prev) == glyph_code
+ -- languages.expand(start,pglyph and prev)
+ -- -- we can have a different start now
+ -- elseif subtype ~= discretionarydisc_code then
+ -- prev = getprev(start)
+ -- pglyph = prev and getid(prev) == glyph_code
+ -- languages.expand(start,pglyph and prev)
+ -- end
+ local pre, post, replace = getdisc(start)
+ local indeed = false
+ if pre then
+ local okay = false
+ if not prev then
+ prev = getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ pre, okay = inject_begin(pre,prev,keeptogether,krn,okay)
+ end
+ pre, okay = process_list(pre,keeptogether,krn,false,okay)
+ if okay then
+ indeed = true
+ end
+ end
+ if post then
+ local okay = false
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ post, okay = inject_end(post,next,keeptogether,krn,okay)
+ end
+ post, okay = process_list(post,keeptogether,krn,false,okay)
+ if okay then
+ indeed = true
+ end
+ end
+ if replace then
+ local okay = false
+ if not prev then
+ prev = getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ replace, okay = inject_begin(replace,prev,keeptogether,krn,okay)
+ end
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ replace, okay = inject_end(replace,next,keeptogether,krn,okay)
+ end
+ replace, okay = process_list(replace,keeptogether,krn,false,okay)
+ if okay then
+ indeed = true
+ end
+ elseif prevfont then
+ replace = new_kern(quaddata[prevfont]*krn)
+ indeed = true
+ end
+ if indeed then
+ setdisc(start,pre,post,replace)
+ end
+ bound = false
+ elseif id == kern_code then
+ bound = getsubtype(start) == fontkern_code
+ prev = start
+ previd = id
+ elseif id == glue_code then
+ local subtype = getsubtype(start)
+ if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
+ local width, stretch, shrink, stretch_order, shrink_order = getglue(start)
+ if width > 0 then
+ local w = width + gluefactor * width * krn
+ stretch = stretch * w / width
+ shrink = shrink * w / width
+ if fillup then
+ stretch = 2 * stretch
+ shrink = 2 * shrink
+ stretch_order = 1
+ -- shrink_order = 1 ?
+ end
+ setglue(start,w,stretch,shrink,stretch_order,shrink_order)
+ end
+ end
+ bound = false
+ elseif id == hlist_code or id == vlist_code then
+ local subtype = getsubtype(start)
+ if subtype == unknownlist_code or subtype == boxlist_code then
+ -- special case
+ local b, f = closest_bound(start,getprev)
+ if b then
+ insert_node_before(head,start,kern_injector(fillup,quaddata[f]*krn))
+ end
+ local b, f = closest_bound(start,getnext)
+ if b then
+ insert_node_after(head,start,kern_injector(fillup,quaddata[f]*krn))
+ end
+ end
+ bound = false
+ elseif id == math_code then
+ start = end_of_math(start)
+ bound = false
+ end
+ if start then
+ start = getnext(start)
+ end
+ done = true
+ else
+ local id = getid(start)
+ if id == kern_code then
+ bound = getsubtype(start) == fontkern_code
+ prev = start
+ previd = id
+ start = getnext(start)
+ else
+ bound = false
+ start = getnext(start)
+ end
+ end
+ end
+ if done then
+ -- unset_attributes(a_kerns, head)
+ end
+ end
+ return head
+end
+
+local enabled = false
+
+function kerns.set(factor)
+ if factor ~= v_max then
+ factor = tonumber(factor) or 0
+ end
+ if factor == v_max or factor ~= 0 then
+ if not enabled then
+ enableaction("processors","typesetters.kerns.handler")
+ enabled = true
+ end
+ local a = factors[factor]
+ if not a then
+ a = #mapping + 1
+ factors[factors], mapping[a] = a, factor
+ end
+ factor = a
+ else
+ factor = unsetvalue
+ end
+ texsetattribute(a_kerns,factor)
+ return factor
+end
+
+-- interface
+
+interfaces.implement {
+ name = "setcharacterkerning",
+ actions = kerns.set,
+ arguments = "string"
+}
+
diff --git a/tex/context/base/mkxl/typo-krn.mkxl b/tex/context/base/mkxl/typo-krn.mkxl
index b16bdacc4..4c6aea256 100644
--- a/tex/context/base/mkxl/typo-krn.mkxl
+++ b/tex/context/base/mkxl/typo-krn.mkxl
@@ -15,7 +15,7 @@
\unprotect
-\registerctxluafile{typo-krn}{}
+\registerctxluafile{typo-krn}{autosuffix}
\definesystemattribute[kern][public]
diff --git a/tex/context/base/mkxl/typo-pag.lmt b/tex/context/base/mkxl/typo-pag.lmt
new file mode 100644
index 000000000..9f8a3a1f4
--- /dev/null
+++ b/tex/context/base/mkxl/typo-pag.lmt
@@ -0,0 +1,206 @@
+if not modules then modules = { } end modules ['typo-pag'] = {
+ version = 1.001,
+ comment = "companion to typo-pag.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
+builders = builders or { }
+local builders = builders
+
+builders.paragraphs = builders.paragraphs or { }
+local parbuilders = builders.paragraphs
+
+local nodes = nodes
+local nodecodes = nodes.nodecodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local penalty_code = nodecodes.penalty
+
+local unsetvalue = attributes.unsetvalue
+local a_keeptogether = attributes.private("keeptogether")
+
+local nuts = nodes.nuts
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local takeattr = nuts.takeattr
+local setattr = nuts.setattr
+local getwhd = nuts.getwhd
+local getkern = nuts.getkern
+local setpenalty = nuts.setpenalty
+local getwidth = nuts.getwidth
+local getdepth = nuts.getdepth
+
+local insert_node_after = nuts.insert_after
+local new_penalty = nuts.pool.penalty
+
+local trace_keeptogether = false
+local report_keeptogether = logs.reporter("parbuilders","keeptogether")
+
+local enableaction = nodes.tasks.enableaction
+
+local cache = { }
+local last = 0
+local enabled = false
+
+trackers.register("parbuilders.keeptogether", function(v) trace_keeptogether = v end)
+
+-- todo: also support lines = 3 etc (e.g. dropped caps) but how to set that
+-- when no hlists are there ?
+
+function parbuilders.registertogether(line,specification) -- might change
+ if not specification then
+ return
+ end
+ if not enabled then
+ enableaction("finalizers","builders.paragraphs.keeptogether")
+ end
+ local a = getattr(line,a_keeptogether)
+ local c = a and cache[a]
+ if c then
+ local height = specification.height
+ local depth = specification.depth
+ local slack = specification.slack
+ if height and height > c.height then
+ c.height = height
+ end
+ if depth and depth > c.depth then
+ c.depth = depth
+ end
+ if slack and slack > c.slack then
+ c.slack = slack
+ end
+ else
+ last = last + 1
+ cache[last] = specification
+ if not specification.height then
+ specification.height = 0
+ end
+ if not specification.depth then
+ specification.depth = 0
+ end
+ if not specification.slack then
+ specification.slack = 0
+ end
+ setattr(line,a_keeptogether,last)
+ end
+ if trace_keeptogether then
+ local a = a or last
+ local c = cache[a]
+ local noflines = specification.lineheight
+ local height = c.height
+ local depth = c.depth
+ local slack = c.slack
+ if not noflines or noflines == 0 then
+ noflines = "unknown"
+ else
+ noflines = math.round((height + depth - slack) / noflines)
+ end
+ report_keeptogether("registered, index %s, height %p, depth %p, slack %p, noflines %a",a,height,depth,slack,noflines)
+ end
+end
+
+local function keeptogether(start,a,specification)
+ local current = getnext(start)
+ local previous = start
+ local total = getdepth(previous)
+ local slack = specification.slack
+ local threshold = specification.depth - slack
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %p, threshold %p, slack %p","list",a,total,threshold,slack)
+ end
+ while current do
+ local id = getid(current)
+ if id == vlist_code or id == hlist_code then
+ local wd, ht, dp = getwhd(current)
+ total = total + ht + dp
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %p, threshold %p","list",a,total,threshold)
+ end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
+ end
+ else
+ break
+ end
+ elseif id == glue_code then
+ -- hm, breakpoint, maybe turn this into kern
+ total = total + getwidth(current)
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold)
+ end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
+ end
+ else
+ break
+ end
+ elseif id == kern_code then
+ total = total + getkern(current)
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold)
+ end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
+ end
+ else
+ break
+ end
+ elseif id == penalty_code then
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ end
+ setpenalty(current,10000)
+ else
+ break
+ end
+ end
+ previous = current
+ current = getnext(current)
+ end
+end
+
+-- also look at first non glue/kern node e.g for a dropped caps
+
+-- todo: find_attribute and unset_attributes instead of takeattr
+
+function parbuilders.keeptogether(head)
+ local done = false -- can go
+ local current = head
+ while current do
+ if getid(current) == hlist_code then
+ local a = takeattr(current,a_keeptogether)
+ if a and a > 0 then
+ local specification = cache[a]
+ if specification then
+ keeptogether(current,a,specification)
+ -- this is tricky ... we need a better resetter, maybe some
+ -- injected latelua or a gc method on a property (interesting
+ -- experiment)
+ cache[a] = nil
+ done = true
+ end
+ end
+ end
+ current = getnext(current)
+ end
+ return head, done
+end
diff --git a/tex/context/base/mkxl/typo-pag.mkxl b/tex/context/base/mkxl/typo-pag.mkxl
index 07443eb16..b34ff079b 100644
--- a/tex/context/base/mkxl/typo-pag.mkxl
+++ b/tex/context/base/mkxl/typo-pag.mkxl
@@ -15,6 +15,6 @@
\unprotect
-\registerctxluafile{typo-pag}{}
+\registerctxluafile{typo-pag}{autosuffix}
\protect \endinput
diff --git a/tex/context/base/mkxl/typo-spa.lmt b/tex/context/base/mkxl/typo-spa.lmt
new file mode 100644
index 000000000..84dd0696d
--- /dev/null
+++ b/tex/context/base/mkxl/typo-spa.lmt
@@ -0,0 +1,255 @@
+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 getattr = nuts.getattr
+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 unset_attributes = nuts.unset_attributes
+local find_attribute = nuts.find_attribute
+
+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 = find_attribute(head, a_spacings)
+ if start then
+ local done = false
+ -- 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 = getattr(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
+ done = true
+ 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
+ if done then
+ -- unset_attributes(a_spacings,head)
+ 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/typo-spa.mkxl b/tex/context/base/mkxl/typo-spa.mkxl
index 4daaac100..42825b022 100644
--- a/tex/context/base/mkxl/typo-spa.mkxl
+++ b/tex/context/base/mkxl/typo-spa.mkxl
@@ -15,7 +15,7 @@
\unprotect
-\registerctxluafile{typo-spa}{}
+\registerctxluafile{typo-spa}{autosuffix}
\definesystemattribute[spacing][public]
diff --git a/tex/context/modules/mkiv/s-magazine-basic.mkiv b/tex/context/modules/mkiv/s-magazine-basic.mkiv
index d45fe6f60..c5995162a 100644
--- a/tex/context/modules/mkiv/s-magazine-basic.mkiv
+++ b/tex/context/modules/mkiv/s-magazine-basic.mkiv
@@ -110,8 +110,9 @@
\doifoddpageelse {
\reuseMPgraphic{rightpaper}
} {
- \reuseMPgraphic{leftpaper}}
+ \reuseMPgraphic{leftpaper}
}
+ }
\stopsetups
@@ -459,8 +460,8 @@
\definetyping[xtyping] [style=\ttx]
\definetyping[xxtyping][style=\ttxx]
-\definetyping[ntyping] \setuptyping[ntyping][style=\narrowtt]
-\definetype [ntype] \setuptype [ntype] [style=\narrowtt]
+% \definetyping[ntyping] \setuptyping[ntyping][style=\narrowtt]
+% \definetype [ntype] \setuptype [ntype] [style=\narrowtt]
\setupdocument
[main={\doifelsemode{atpragma}{This Way}{My Way}},
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index b94ad3846..9515034ab 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-03 18:56
+-- merge date : 2020-12-04 20:19
do -- begin closure to overcome local limits and interference