From 0477f879e2b574ad568732ad03784e5df1952fb7 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Fri, 4 Dec 2020 21:16:33 +0100 Subject: 2020-12-04 20:21:00 --- tex/context/base/mkii/cont-new.mkii | 2 +- tex/context/base/mkii/context.mkii | 2 +- tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/context.mkiv | 2 +- tex/context/base/mkiv/status-files.pdf | Bin 26093 -> 26096 bytes tex/context/base/mkiv/status-lua.pdf | Bin 255687 -> 255677 bytes tex/context/base/mkiv/typo-spa.lua | 246 -------- tex/context/base/mkxl/back-out.lmt | 4 +- tex/context/base/mkxl/back-trf.lmt | 8 +- tex/context/base/mkxl/cont-log.mkxl | 2 +- tex/context/base/mkxl/cont-new.mkxl | 2 +- tex/context/base/mkxl/context.mkxl | 2 +- tex/context/base/mkxl/grph-inc.mkxl | 6 - tex/context/base/mkxl/lpdf-lmt.lmt | 7 +- tex/context/base/mkxl/lpdf-tag.lmt | 3 + tex/context/base/mkxl/meta-ini.mkxl | 2 +- tex/context/base/mkxl/node-nut.lmt | 1 + tex/context/base/mkxl/page-bck.mkxl | 4 +- tex/context/base/mkxl/syst-ini.mkxl | 9 +- tex/context/base/mkxl/tabl-tbl.mkxl | 8 +- tex/context/base/mkxl/typo-brk.lmt | 498 ++++++++++++++++ tex/context/base/mkxl/typo-brk.mkxl | 2 +- tex/context/base/mkxl/typo-cap.lmt | 272 +++++---- tex/context/base/mkxl/typo-cap.mkxl | 3 +- tex/context/base/mkxl/typo-dig.lmt | 181 ++++++ tex/context/base/mkxl/typo-dig.mkxl | 2 +- tex/context/base/mkxl/typo-krn.lmt | 630 +++++++++++++++++++++ tex/context/base/mkxl/typo-krn.mkxl | 2 +- tex/context/base/mkxl/typo-pag.lmt | 206 +++++++ tex/context/base/mkxl/typo-pag.mkxl | 2 +- tex/context/base/mkxl/typo-spa.lmt | 255 +++++++++ tex/context/base/mkxl/typo-spa.mkxl | 2 +- tex/context/modules/mkiv/s-magazine-basic.mkiv | 7 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 2 +- 34 files changed, 1947 insertions(+), 429 deletions(-) delete mode 100644 tex/context/base/mkiv/typo-spa.lua create mode 100644 tex/context/base/mkxl/typo-brk.lmt create mode 100644 tex/context/base/mkxl/typo-dig.lmt create mode 100644 tex/context/base/mkxl/typo-krn.lmt create mode 100644 tex/context/base/mkxl/typo-pag.lmt create mode 100644 tex/context/base/mkxl/typo-spa.lmt (limited to 'tex') 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 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index 29161ec70..844a0c16e 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf 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 -- cgit v1.2.3