diff options
author | Hans Hagen <pragma@wxs.nl> | 2020-05-07 11:47:12 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2020-05-07 11:47:12 +0200 |
commit | 352a2686282e95b2869728f8f321688f7e216d80 (patch) | |
tree | a0cd6d8cd35aaf6c51632307786e4083e25c0df8 /tex/context | |
parent | 3d0fae7aaf79674a41d2bdaf5b3c2a3a4d8113db (diff) | |
download | context-352a2686282e95b2869728f8f321688f7e216d80.tar.gz |
2020-05-07 11:00:00
Diffstat (limited to 'tex/context')
45 files changed, 1738 insertions, 560 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index aa3436495..879459521 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.04.30 11:10} +\newcontextversion{2020.05.07 10:57} %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 862a6e087..4876e687c 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.04.30 11:10} +\edef\contextversion{2020.05.07 10:57} %D For those who want to use this: diff --git a/tex/context/base/mkiv/back-pdf.mkiv b/tex/context/base/mkiv/back-pdf.mkiv index ec1c641e6..697aa311f 100644 --- a/tex/context/base/mkiv/back-pdf.mkiv +++ b/tex/context/base/mkiv/back-pdf.mkiv @@ -65,9 +65,9 @@ \unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax} \unexpanded\def\pdfrefobj {\clf_pdfrefobj } -\unexpanded\def\pdfrestore {\clf_restore} -\unexpanded\def\pdfsave {\clf_save} -\unexpanded\def\pdfsetmatrix{\clf_setmatrix} +\unexpanded\def\pdfrestore {\pdfextension restore} +\unexpanded\def\pdfsave {\pdfextension save} +\unexpanded\def\pdfsetmatrix{\pdfextension setmatrix} \let\pdfxform \saveboxresource \let\pdflastxform \lastsavedboxresourceindex diff --git a/tex/context/base/mkiv/back-pdf.mkxl b/tex/context/base/mkiv/back-pdf.mkxl index ab65458c5..6538a8309 100644 --- a/tex/context/base/mkiv/back-pdf.mkxl +++ b/tex/context/base/mkiv/back-pdf.mkxl @@ -65,11 +65,11 @@ \unexpanded\def\pdfliteral {\clf_pdfliteral} \unexpanded\def\pdfobj {\clf_pdfobj}% \unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax} -\unexpanded\def\pdfrefobj {\clf_pdfrefobj } +\unexpanded\def\pdfrefobj {\clf_pdfrefobj} -\unexpanded\def\pdfrestore {\clf_restore} -\unexpanded\def\pdfsave {\clf_save} -\unexpanded\def\pdfsetmatrix{\clf_setmatrix} +\unexpanded\def\pdfrestore {\pdfextension restore} +\unexpanded\def\pdfsave {\pdfextension save} +\unexpanded\def\pdfsetmatrix{\pdfextension setmatrix} \let\pdfxform \saveboxresource \let\pdflastxform \lastsavedboxresourceindex diff --git a/tex/context/base/mkiv/back-pdp.lua b/tex/context/base/mkiv/back-pdp.lua index 6111cf469..6e663f1dd 100644 --- a/tex/context/base/mkiv/back-pdp.lua +++ b/tex/context/base/mkiv/back-pdp.lua @@ -273,9 +273,12 @@ implement { name = "pdffeedback", actions = pdffeedback } -- for the moment (tikz) -implement { name = "pdfliteral", actions = pdfliteral } -implement { name = "pdfobj", actions = pdfobj } -implement { name = "pdflastobj", actions = pdflastobj } -implement { name = "pdfrefobj", actions = pdfrefobj } ---------- { name = "pdfannot", actions = pdfannot } ---------- { name = "pdfdest", actions = pdfdest } +implement { name = "pdfliteral", actions = pdfliteral } +implement { name = "pdfobj", actions = pdfobj } +implement { name = "pdflastobj", actions = pdflastobj } +implement { name = "pdfrefobj", actions = pdfrefobj } +--------- { name = "pdfannot", actions = pdfannot } +--------- { name = "pdfdest", actions = pdfdest } +--------- { name = "pdfsave", actions = pdfsave } +--------- { name = "pdfrestore", actions = pdfrestore } +--------- { name = "pdfsetmatrix", actions = pdfsetmatrix } diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index 56cbfe3fa..5f33f9c2a 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -392,7 +392,7 @@ local interfacescanners = setmetatablenewindex(function(t,k,v) -- rawset(t,k,v) end) -function interfaces.registerscanner(name,action,protected,public,call) +function interfaces.registerscanner(name,action,protected,public,valuetype) rawset(interfacescanners,name,action) if storedscanners[name] then -- report_cld("warning: scanner %a is already set (mode 2a)",name) @@ -405,7 +405,7 @@ function interfaces.registerscanner(name,action,protected,public,call) local n = registerfunction("interfaces.scanners."..name,true) storedscanners[name] = n local name = public and name or ("clf_" .. name) - setluatoken(name,n,"global",protected and "protected" or "") + setluatoken(name,n,"global",protected and "protected" or "",valuetype or "") else storedscanners[name] = true -- report_cld("installing interface scanner: %s (mode 2c)",name) diff --git a/tex/context/base/mkiv/cldf-scn.lua b/tex/context/base/mkiv/cldf-scn.lua index d0b16e034..d79383866 100644 --- a/tex/context/base/mkiv/cldf-scn.lua +++ b/tex/context/base/mkiv/cldf-scn.lua @@ -77,8 +77,7 @@ function interfaces.implement(specification) if scanners[name] and not specification.overload then report("warning: 'scanners.%s' is redefined",name) end - -- scanners[name] = scanner -- we now use: - register(name,scanner,specification.protected,specification.public,specification.call) + register(name,scanner,specification.protected,specification.public,specification.valuetype) if private then return end diff --git a/tex/context/base/mkiv/colo-ini.mkiv b/tex/context/base/mkiv/colo-ini.mkiv index c489635de..71c823f8a 100644 --- a/tex/context/base/mkiv/colo-ini.mkiv +++ b/tex/context/base/mkiv/colo-ini.mkiv @@ -1380,7 +1380,11 @@ % \normal added else fails in metafun manual (leaders do a hard scan) -\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed ! +% \unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed ! +% +% I really need to sort this out! + +\unexpanded\def\forcecolorhack{\leaders\hrule height\zeropoint depth\zeropoint\hskip\zeropoint\relax} % relax is needed ! %D We default to the colors defined in \type {colo-imp-rgb} and %D support both \RGB\ and \CMYK\ output. Transparencies are defined diff --git a/tex/context/base/mkiv/colo-ini.mkxl b/tex/context/base/mkiv/colo-ini.mkxl index e821fb7e2..47d6cc8a1 100644 --- a/tex/context/base/mkiv/colo-ini.mkxl +++ b/tex/context/base/mkiv/colo-ini.mkxl @@ -1322,7 +1322,11 @@ % \normal added else fails in metafun manual (leaders do a hard scan) -\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed ! +% \unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed ! +% +% I really need to sort this out! + +\unexpanded\def\forcecolorhack{\leaders\hrule height\zeropoint depth\zeropoint\hskip\zeropoint\relax} % relax is needed ! %D We default to the colors defined in \type {colo-imp-rgb} and %D support both \RGB\ and \CMYK\ output. Transparencies are defined diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 9ce4dacf5..f8c96cab7 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.04.30 11:10} +\newcontextversion{2020.05.07 10:57} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 6f17f2868..d7310826b 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.04.30 11:10} +\edef\contextversion{2020.05.07 10:57} \edef\contextkind {beta} %D Kind of special: diff --git a/tex/context/base/mkiv/context.mkxl b/tex/context/base/mkiv/context.mkxl index 4bdb96da8..7ad162369 100644 --- a/tex/context/base/mkiv/context.mkxl +++ b/tex/context/base/mkiv/context.mkxl @@ -29,7 +29,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2020.04.30 11:10} +\edef\contextversion{2020.05.07 10:57} \edef\contextkind {beta} %D Kind of special: diff --git a/tex/context/base/mkiv/data-ini.lua b/tex/context/base/mkiv/data-ini.lua index 2e9010085..3c1531019 100644 --- a/tex/context/base/mkiv/data-ini.lua +++ b/tex/context/base/mkiv/data-ini.lua @@ -75,6 +75,7 @@ end do + local oldhome = osgetenv('HOME') local homedir = osgetenv(ostype == "windows" and 'USERPROFILE' or 'HOME') or '' if not homedir or homedir == "" then @@ -86,6 +87,7 @@ do ossetenv("HOME", homedir) -- can be used in unix cnf files ossetenv("USERPROFILE",homedir) -- can be used in windows cnf files + environment.oldhome = oldhome environment.homedir = homedir end diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua index 72b0a038f..627847efa 100644 --- a/tex/context/base/mkiv/font-cff.lua +++ b/tex/context/base/mkiv/font-cff.lua @@ -612,6 +612,9 @@ do parsedictionaries = function(data,dictionaries,what) stack = { } strings = data.strings + if trace_charstrings then + report("charstring format %a",what) + end for i=1,#dictionaries do top = 0 result = what == "cff" and { @@ -1517,7 +1520,7 @@ do end end else - -- error + top = top - nofregions * n end end diff --git a/tex/context/base/mkiv/font-con.lua b/tex/context/base/mkiv/font-con.lua index 1bb63aa51..04c42061e 100644 --- a/tex/context/base/mkiv/font-con.lua +++ b/tex/context/base/mkiv/font-con.lua @@ -210,60 +210,45 @@ end -- we default to false, so a macro package has to enable it explicitly. In -- LuaTeX the fullname is used to identify a font as being unique. -constructors.sharefonts = false -constructors.nofsharedfonts = 0 -local sharednames = { } +local nofinstances = 0 +local instances = setmetatableindex(function(t,k) + nofinstances = nofinstances + 1 + t[k] = nofinstances + return nofinstances +end) function constructors.trytosharefont(target,tfmdata) - if constructors.sharefonts then -- not robust ! - local characters = target.characters - local n = 1 - local t = { target.psname } - local u = sortedkeys(characters) - for i=1,#u do - local k = u[i] - n = n + 1 ; t[n] = k - n = n + 1 ; t[n] = characters[k].index or k + local properties = target.properties + local instance = properties.instance + if instance then + local fullname = target.fullname + local fontname = target.fontname + local psname = target.psname + local format = tfmdata.properties.format + if format == "opentype" then + target.streamprovider = 1 + elseif format == "truetype" then + target.streamprovider = 2 + else + target.streamprovider = 0 end - local h = md5.HEX(concat(t," ")) - local s = sharednames[h] - if s then - if trace_defining then - report_defining("font %a uses backend resources of font %a",target.fullname,s) + if target.streamprovider > 0 then + if fullname then + fullname = fullname .. ":" .. instances[instance] + target.fullname = fullname + end + if fontname then + fontname = fontname .. ":" .. instances[instance] + target.fontname = fontname + end + if psname then + psname = psname .. ":" .. instances[instance] + target.psname = psname end - target.fullname = s - constructors.nofsharedfonts = constructors.nofsharedfonts + 1 - target.properties.sharedwith = s - else - sharednames[h] = target.fullname end end end --- function constructors.enhanceparameters(parameters) --- local xheight = parameters.x_height --- local quad = parameters.quad --- local space = parameters.space --- local stretch = parameters.space_stretch --- local shrink = parameters.space_shrink --- local extra = parameters.extra_space --- local slant = parameters.slant --- -- synonyms --- parameters.xheight = xheight --- parameters.spacestretch = stretch --- parameters.spaceshrink = shrink --- parameters.extraspace = extra --- parameters.em = quad --- parameters.ex = xheight --- parameters.slantperpoint = slant --- parameters.spacing = { --- width = space, --- stretch = stretch, --- shrink = shrink, --- extra = extra, --- } --- end - local synonyms = { exheight = "x_height", xheight = "x_height", diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 6f8354de8..9e59c66bc 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -173,6 +173,7 @@ if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then end constructors.sharefonts = true -- experimental +constructors.nofsharedfonts = 0 constructors.nofsharedhashes = 0 constructors.nofsharedvectors = 0 constructors.noffontsloaded = 0 @@ -202,6 +203,7 @@ do local shares = { } local hashes = { } + local nofinstances = 0 local instances = setmetatableindex(function(t,k) nofinstances = nofinstances + 1 @@ -240,7 +242,7 @@ do end if psname then -- this one is used for the funny prefix in font names in pdf - -- so it has ot be kind of unique in order to avoid subset prefix + -- so it has to be kind of unique in order to avoid subset prefix -- clashes being reported psname = psname .. ":" .. instances[instance] target.psname = psname diff --git a/tex/context/base/mkiv/font-def.lua b/tex/context/base/mkiv/font-def.lua index e287bf79c..09f2e2c32 100644 --- a/tex/context/base/mkiv/font-def.lua +++ b/tex/context/base/mkiv/font-def.lua @@ -207,9 +207,6 @@ function resolvers.name(specification) features.normal = normal end normal.instance = instance - -- if not callbacks.supported.glyph_stream_provider then - -- normal.variableshapes = true -- for the moment - -- end end -- local suffix = lower(suffixonly(resolved)) diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index 3058be37b..f8794bcde 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -302,7 +302,7 @@ end) -- values can be anything the min/max permits so we can either think of -- real values of a fraction along the axis (probably easier) --- wght:400,wdth:100,ital:1 +-- wght=400,wdth=100,ital=1 local function axistofactors(str) local t = settings_to_hash(str) diff --git a/tex/context/base/mkiv/font-imp-italics.lua b/tex/context/base/mkiv/font-imp-italics.lua index 83c785d38..3e172bede 100644 --- a/tex/context/base/mkiv/font-imp-italics.lua +++ b/tex/context/base/mkiv/font-imp-italics.lua @@ -79,33 +79,25 @@ if context then registerotffeature(specification) registerafmfeature(specification) -end - --- no longer used - --- if context then --- --- -- local function initializemathitalics(tfmdata,value) -- yes no delay --- -- tfmdata.properties.mathitalics = toboolean(value) --- -- end --- -- --- -- local specification = { --- -- name = "mathitalics", --- -- description = "use alternative math italic correction", --- -- initializers = { --- -- base = initializemathitalics, --- -- node = initializemathitalics, --- -- } --- -- } --- -- --- -- registerotffeature(specification) --- -- registerafmfeature(specification) --- --- end - --- -- also not used, only when testing - -if context then + -- no longer used + + -- local function initializemathitalics(tfmdata,value) -- yes no delay + -- tfmdata.properties.mathitalics = toboolean(value) + -- end + -- + -- local specification = { + -- name = "mathitalics", + -- description = "use alternative math italic correction", + -- initializers = { + -- base = initializemathitalics, + -- node = initializemathitalics, + -- } + -- } + -- + -- registerotffeature(specification) + -- registerafmfeature(specification) + + -- only used when testing local letter = characters.is_letter local always = true diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi index b2f42f0c2..133143224 100644 --- a/tex/context/base/mkiv/font-lib.mkvi +++ b/tex/context/base/mkiv/font-lib.mkvi @@ -50,12 +50,12 @@ %registerctxluafile{font-osm}{} \ifcase\contextlmtxmode - \ifnum\luatexversion>111 - \doifelsefileexists{font-ocm.lua} - {\registerctxluafile{font-ocm}{}} % mkiv new - {\registerctxluafile{font-ocl}{}} + \ifcase\directlua{tex.print(callback.list()["provide_charproc_data"] == false and 1 or 0)}\relax + % this is the generic variant that will become luatex-fonts-ocl once we have + % more recent versions of luatex 1.13/1.14 on the garden + \registerctxluafile{font-ocl}{} \else - \registerctxluafile{font-ocl}{} % generic (will become luatex-fonts-ocl) + \registerctxluafile{font-ocm}{} \fi \else \registerctxluafile{font-ogr}{} % lmtx diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index 1890e5ec5..e6a38af5c 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -8,10 +8,6 @@ if not modules then modules = { } end modules ['font-ocl'] = { -- todo : user list of colors -if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then - return -end - local tostring, tonumber, next = tostring, tonumber, next local round, max = math.round, math.round local gsub, find = string.gsub, string.find @@ -151,85 +147,17 @@ local function convert(t,k) return v end -local start = { "pdf", "mode", "font" } -- force text mode (so get q Q right) ------ stop = { "pdf", "mode", "page" } -- force page mode (else overlap) -local push = { "pdf", "page", "q" } -local pop = { "pdf", "page", "Q" } - --- -- This one results in color directives inside BT ET but has less q Q pairs. It --- -- only shows the first glyph in acrobat and nothing more. No problem with other --- -- renderers. --- --- local function initializeoverlay(tfmdata,kind,value) -- hm, always value --- if value then --- local resources = tfmdata.resources --- local palettes = resources.colorpalettes --- if palettes then --- -- --- local converted = resources.converted --- if not converted then --- converted = setmetatableindex(convert) --- resources.converted = converted --- end --- local colorvalues = sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or { } --- local classes = #colorvalues --- if classes == 0 then --- return --- end --- -- --- local characters = tfmdata.characters --- local descriptions = tfmdata.descriptions --- local properties = tfmdata.properties --- -- --- properties.virtualized = true --- tfmdata.fonts = { --- { id = 0 } --- } --- -- --- local getactualtext = otf.getactualtext --- local default = colorvalues[#colorvalues] --- local b, e = getactualtext(tounicode(0xFFFD)) --- local actualb = { "pdf", "page", b } -- saves tables --- local actuale = { "pdf", "page", e } -- saves tables --- -- --- for unicode, character in next, characters do --- local description = descriptions[unicode] --- if description then --- local colorlist = description.colors --- if colorlist then --- local u = description.unicode or characters[unicode].unicode --- local w = character.width or 0 --- local s = #colorlist --- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same --- local t = { --- start, --- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }, --- push, --- } --- local n = 3 --- local l = nil --- for i=1,s do --- local entry = colorlist[i] --- local v = colorvalues[entry.class] or default --- if v and l ~= v then --- n = n + 1 t[n] = v --- l = v --- end --- n = n + 1 t[n] = charcommand[entry.slot] --- if s > 1 and i < s and goback then --- n = n + 1 t[n] = goback --- end --- end --- n = n + 1 t[n] = pop --- n = n + 1 t[n] = actuale --- n = n + 1 t[n] = stop --- character.commands = t --- end --- end --- end --- end --- end --- end +-- At some point 'font' mode was added to the engine and we can assume that most distributions +-- ship a luatex that has it; ancient versions are no longer supported anyway. Begin 2020 there +-- was an actualtext related mail exchange with RM etc. that might result in similar mode keys +-- in other tex->pdf programs because there is a bit of inconsistency in the way this is dealt +-- with. Best is not to touch this code too much. + +local mode = { "pdf", "mode", "font" } +local push = { "pdf", "page", "q" } +local pop = { "pdf", "page", "Q" } + +-- see context git repository for older variant (pre 20200501 cleanup) local function initializeoverlay(tfmdata,kind,value) if value then @@ -278,10 +206,11 @@ local function initializeoverlay(tfmdata,kind,value) local s = #colorlist local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same local t = { + mode, not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }, push, } - local n = 2 + local n = 3 local l = nil for i=1,s do local entry = colorlist[i] @@ -436,7 +365,7 @@ do local savedata = io.savedata local remove = os.remove - if context and xml.convert then +if context then local xmlconvert = xml.convert local xmlfirst = xml.first @@ -451,13 +380,13 @@ do return data end - else +else function otfsvg.filterglyph(entry,index) -- can be overloaded return entry.data end - end +end local runner = sandbox and sandbox.registerrunner { name = "otfsvg", @@ -484,6 +413,16 @@ do -- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of -- ugly overhead. Bah. + local new = nil + + local function inkscapeformat(suffix) + if new == nil then + new = os.resultof("inkscape --version") or "" + new = new == "" or not find(new,"Inkscape%s*0") + end + return new and "filename" or suffix + end + function otfsvg.topdf(svgshapes,tfmdata) local pdfshapes = { } local inkscape = runner() @@ -493,7 +432,7 @@ do local nofshapes = #svgshapes local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"] local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"] - local f_convert = formatters["%s --export-pdf=%s\n"] + local f_convert = formatters["%s --export-%s=%s\n"] local filterglyph = otfsvg.filterglyph local nofdone = 0 local processed = { } @@ -507,7 +446,7 @@ do local svgfile = f_svgfile(index) local pdffile = f_pdffile(index) savedata(svgfile,data) - inkscape:write(f_convert(svgfile,pdffile)) + inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile)) processed[index] = true nofdone = nofdone + 1 if nofdone % 25 == 0 then diff --git a/tex/context/base/mkiv/font-ocm.lua b/tex/context/base/mkiv/font-ocm.lua new file mode 100644 index 000000000..131b0ed13 --- /dev/null +++ b/tex/context/base/mkiv/font-ocm.lua @@ -0,0 +1,874 @@ +if not modules then modules = { } end modules ['font-ocm'] = { + version = 1.001, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if not context then + return +elseif CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then + return +else + -- Maybe I'll also make a generic variant but for now I just test this in + -- MkIV. After all, color fonts are not that much used (and generic is for + -- serious looking articles and books and not for fancy documents using + -- emoji.) Below is a quick and dirty implementation. Also, it looks like + -- these features were never used outside context anyway (in spite of being + -- in generic). +end + +local tostring, tonumber, next = tostring, tonumber, next +local round, max = math.round, math.round +local sortedkeys, sortedhash, concat = table.sortedkeys, table.sortedhash, table.concat +local setmetatableindex = table.setmetatableindex +local formatters = string.formatters + +local otf = fonts.handlers.otf +local otfregister = otf.features.register +local bpfactor = number.dimenfactors.bp +local typethree = { } + +callback.register("provide_charproc_data",function(action,f,...) + local registered = typethree[f] + if registered then + return registered(action,f,...) + else + return 0, 0 -- this will also disable further calls + end +end) + +local defaults = { + [1] = function() return 0, 0 end, + [2] = function() return 0, 0 end, + [3] = function() return 0.001, "" end, +} + +local function registeractions(t) + return { + [1] = t.preroll or defaults[1], + [2] = t.collect or defaults[2], + [3] = t.wrapup or defaults[3], + } +end + +local function registertypethreeresource(specification,n,o) + specification.usedobjects["X"..n] = lpdf.reference(o) +end + +local function registertypethreefont(specification,n,o) + specification.usedfonts["F"..n] = lpdf.reference(o) +end + +local function typethreeresources(specification) + local usedobjects = specification.usedobjects + local usedfonts = specification.usedfonts + local resources = { } + if next(usedobjects) then + resources[#resources+1] = "/XObject << " .. usedobjects() .. " >>" + end + if next(usedfonts) then + resources[#resources+1] = "/Font << " .. usedfonts() .. " >>" + end + -- resources[#resources+1] = lpdf.collectedresources() + specification.usedfonts = nil + specification.usedobjects = nil + return concat(resources, " ") +end + +local function registerfont(specification,actions) + specification.usedfonts = lpdf.dictionary() + specification.usedobjects = lpdf.dictionary() + typethree[specification.id] = function(action,f,c) + return actions[action](specification,f,c) + end +end + +fonts.handlers.typethree = { + register = function(id,handler) + -- needed for manual + if not typethree[id] then + logs.report("fonts","low level Type3 handler registered for font with id %i",id) + typethree[id] = handler + end + end +} + +local initializeoverlay do + + local f_color = formatters["%.3f %.3f %.3f rg"] + local f_gray = formatters["%.3f g"] + local sharedpalettes = { } + local colors = attributes.list[attributes.private('color')] or { } + local transparencies = attributes.list[attributes.private('transparency')] or { } + + function otf.registerpalette(name,values) + sharedpalettes[name] = values + local color = lpdf.color + local transparency = lpdf.transparency + local register = colors.register + for i=1,#values do + local v = values[i] + if v == "textcolor" then + values[i] = false + else + local c = nil + local t = nil + if type(v) == "table" then + c = register(name,"rgb", + max(round((v.r or 0)*255),255)/255, + max(round((v.g or 0)*255),255)/255, + max(round((v.b or 0)*255),255)/255 + ) + else + c = colors[v] + t = transparencies[v] + end + if c and t then + values[i] = color(1,c) .. " " .. transparency(t) + elseif c then + values[i] = color(1,c) + elseif t then + values[i] = color(1,t) + end + end + end + end + + local function convert(t,k) + local v = { } + for i=1,#k do + local p = k[i] + local r, g, b = p[1], p[2], p[3] + if r == g and g == b then + v[i] = f_gray(r/255) + else + v[i] = f_color(r/255,g/255,b/255) + end + end + t[k] = v + return v + end + + -- This is by no means watertight (the id mess) especially because we + -- don't know it yet. Instead we can just assemble here and avoid the + -- box approach. I might do that (so then we need to pass fonts and + -- extra resource entries. + + local f_stream = formatters["%s 0 d0 %s 0 0 %s 0 %s cm /X%i Do"] + local fontorder = 0 + local actions = registeractions { + + preroll = function(specification,f,c) + local data = specification.delegated[c] + local colorlist = data.colorlist + local colorvalues = specification.colorvalues + local default = specification.default + local mainid = specification.mainid + local t = { "\\typethreefont{", mainid, "}" } + local n = 3 + local l = nil + local m = #colorlist + for i=1,m do + local entry = colorlist[i] + local v = colorvalues[entry.class] or default + if v and l ~= v then + n = n + 1 ; t[n] = "\\typethreecode{" + n = n + 1 ; t[n] = v + n = n + 1 ; t[n] = "}" + l = v + end + if i < m then + n = n + 1 ; t[n] = "\\typethreechar{" + else + n = n + 1 ; t[n] = "\\typethreelast{" + end + n = n + 1 ; t[n] = entry.slot + n = n + 1 ; t[n] = "}" + end + token.set_macro("typethreemacro",concat(t)) + tex.runtoks("typethreetoks") + registertypethreeresource(specification,c,tex.saveboxresource(0,nil,lpdf.collectedresources(),true)) + -- registertypethreefont(specification,mainid,lpdf.reference(lpdf.getfontobjnumber(mainid))) + return 0, 0 + end, + + collect = function(specification,f,c) + local parameters = specification.parameters + local data = specification.delegated[c] + local factor = parameters.hfactor + local units = parameters.units + local width = (data.width or 0) / factor + local scale = 100 + local factor = units * bpfactor -- / scale + local depth = (data.depth or 0)*factor + local shift = - depth / (10*units/1000) + local object = pdf.immediateobj("stream",f_stream(width,scale,scale,shift,c)) + return object, width + end, + + wrapup = function(specification,f) + return 0.001, typethreeresources(specification) + end, + + } + + local function register(specification) + registerfont(specification,actions) + end + + initializeoverlay = function(tfmdata,kind,value) + if value then + local resources = tfmdata.resources + local palettes = resources.colorpalettes + if palettes then + local converted = resources.converted + if not converted then + converted = setmetatableindex(convert) + resources.converted = converted + end + local colorvalues = sharedpalettes[value] + local default = false -- so the text color (bad for icon overloads) + if colorvalues then + default = colorvalues[#colorvalues] + else + colorvalues = converted[palettes[tonumber(value) or 1] or palettes[1]] or { } + end + local classes = #colorvalues + if classes == 0 then + return + end + -- + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local properties = tfmdata.properties + local parameters = tfmdata.parameters + -- + properties.virtualized = true + -- + local delegated = { } + local index = 0 + local fonts = tfmdata.fonts or { } + local fontindex = #fonts + 1 + tfmdata.fonts = fonts + + local function flush() + if index > 0 then + fontorder = fontorder + 1 + local f = { + characters = delegated, + parameters = parameters, + tounicode = true, + format = "type3", + name = "InternalTypeThreeFont" , -- .. fontorder, + psname = "none", + } + fonts[fontindex] = { + id = font.define(f), + delegated = delegated, + parameters = parameters, + colorvalues = colorvalues, + default = default, + } + end + fontindex = fontindex + 1 + index = 0 + delegated = { } + end + + for unicode, character in sortedhash(characters) do + local description = descriptions[unicode] + if description then + local colorlist = description.colors + if colorlist then + if index == 255 then + flush() + end + index = index + 1 + delegated[index] = { + width = character.width, + height = character.height, + depth = character.depth, + tounicode = character.tounicode, + colorlist = colorlist, + } + character.commands = { + { "slot", fontindex, index }, + } + end + end + end + + flush() + local mainid = font.nextid() + for i=1,#fonts do + local f = fonts[i] + if f.delegated then + f.mainid = mainid + register(f) + end + end + + return true + end + end + end + + otfregister { + name = "colr", + description = "color glyphs", + manipulators = { + base = initializeoverlay, + node = initializeoverlay, + } + } + +end + +do + + local nofstreams = 0 + local f_name = formatters[ [[pdf-glyph-%05i]] ] + local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] + local hashed = { } + local cache = { } + + local openpdf = pdfe.new + + function otf.storepdfdata(pdf) + if pdf then + local done = hashed[pdf] + if not done then + nofstreams = nofstreams + 1 + local f = f_name(nofstreams) + local n = openpdf(pdf,#pdf,f) + done = f_used(n) + hashed[pdf] = done + end + return done + end + end + +end + +local pdftovirtual do + + local f_stream = formatters["%s 0 d0 %s 0 0 %s %s %s cm /X%i Do"] + local fontorder = 0 + local shared = { } + local actions = registeractions { + + preroll = function(specification,f,c) + return 0, 0 + end, + + collect = function(specification,f,c) + local parameters = specification.parameters + local data = specification.delegated[c] + local desdata = data.desdata + local pdfdata = data.pdfdata + local width = desdata.width or 0 + local height = desdata.height or 0 + local depth = desdata.depth or 0 + local factor = parameters.hfactor + local units = parameters.units + local typ = type(pdfdata) + + local dx = 0 + local dy = 0 + local scale = 1 + + if typ == "table" then + data = pdfdata.data + dx = pdfdata.x or pdfdata.dx or 0 + dy = pdfdata.y or pdfdata.dy or 0 + scale = pdfdata.scale or 1 + elseif typ == "string" then + data = pdfdata + dx = 0 + dy = 0 + else + return 0, 0 + end + + if not data then + return 0, 0 + end + + local name = otf.storepdfdata(data) + local xform = shared[name] + + if not xform then + xform = images.embed(images.create { filename = name }) + shared[name] = xform + end + + registertypethreeresource(specification,c,xform.objnum) + + scale = scale * (width / (xform.width * bpfactor)) + dy = - depth + dy +-- dx = 0 +-- dy = 0 + local object = pdf.immediateobj("stream",f_stream(width,scale,scale,dx,dy,c)), width + + return object, width + end, + + wrapup = function(specification,f) + return 1/specification.parameters.units, typethreeresources(specification) + end, + + } + + local function register(specification) + registerfont(specification,actions) + end + + pdftovirtual = function(tfmdata,pdfshapes,kind) -- kind = png|svg + if not tfmdata or not pdfshapes or not kind then + return + end + -- + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local properties = tfmdata.properties + local parameters = tfmdata.parameters + local hfactor = parameters.hfactor + -- + properties.virtualized = true + -- + local storepdfdata = otf.storepdfdata + -- + local delegated = { } + local index = 0 + local fonts = tfmdata.fonts or { } + local fontindex = #fonts + 1 + tfmdata.fonts = fonts + + local function flush() + if index > 0 then + fontorder = fontorder + 1 + local f = { + characters = delegated, + parameters = parameters, + tounicode = true, + format = "type3", + name = "InternalTypeThreeFont" .. fontorder, + psname = "none", + size = parameters.size, + } + fonts[fontindex] = { + id = font.define(f), + delegated = delegated, + parameters = parameters, + } + end + fontindex = fontindex + 1 + index = 0 + delegated = { } + end + + for unicode, character in sortedhash(characters) do + local idx = character.index + if idx then + local pdfdata = pdfshapes[idx] + local description = descriptions[unicode] + if pdfdata and description then + if index == 255 then + flush() + end + index = index + 1 + delegated[index] = { + desdata = description, + width = character.width, + height = character.width, + depth = character.width, + tounicode = character.tounicode, + pdfdata = pdfdata, + } + character.commands = { + { "slot", fontindex, index }, + } + end + end + end + -- + flush() + local mainid = font.nextid() + for i=1,#fonts do + local f = fonts[i] + if f.delegated then + f.mainid = mainid + register(f) + end + end + -- + end + +end + +local initializesvg do + + local otfsvg = otf.svg or { } + otf.svg = otfsvg + otf.svgenabled = true + + local report_svg = logs.reporter("fonts","svg conversion") + + local loaddata = io.loaddata + local savedata = io.savedata + local remove = os.remove + + local xmlconvert = xml.convert + local xmlfirst = xml.first + + function otfsvg.filterglyph(entry,index) + local d = entry.data + if gzip.compressed(d) then + d = gzip.decompress(d) or d + end + local svg = xmlconvert(d) + local root = svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']") + local data = root and tostring(root) + return data + end + + local runner = sandbox and sandbox.registerrunner { + name = "otfsvg", + program = "inkscape", + method = "pipeto", + template = "--export-area-drawing --shell > temp-otf-svg-shape.log", + reporter = report_svg, + } + + if not runner then + -- + -- poor mans variant for generic: + -- + runner = function() + return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w") + end + end + + -- There are svg out there with bad viewBox specifications where shapes lay outside that area, + -- but trying to correct that didn't work out well enough so I discarded that code. BTW, we + -- decouple the inskape run and the loading run because inkscape is working in the background + -- in the files so we need to have unique files. + -- + -- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of + -- ugly overhead. Bah. + + local new = nil + + local function inkscapeformat(suffix) + if new == nil then + new = os.resultof("inkscape --version") or "" + new = new == "" or not find(new,"Inkscape%s*0") + end + return new and "filename" or suffix + end + + function otfsvg.topdf(svgshapes,tfmdata) + local pdfshapes = { } + local inkscape = runner() + if inkscape then + -- local indices = fonts.getindices(tfmdata) + local descriptions = tfmdata.descriptions + local nofshapes = #svgshapes + local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"] + local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"] + local f_convert = formatters["%s --export-%s=%s\n"] + local filterglyph = otfsvg.filterglyph + local nofdone = 0 + local processed = { } + report_svg("processing %i svg containers",nofshapes) + statistics.starttiming() + for i=1,nofshapes do + local entry = svgshapes[i] + for index=entry.first,entry.last do + local data = filterglyph(entry,index) + if data and data ~= "" then + local svgfile = f_svgfile(index) + local pdffile = f_pdffile(index) + savedata(svgfile,data) + inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile)) + processed[index] = true + nofdone = nofdone + 1 + if nofdone % 25 == 0 then + report_svg("%i shapes submitted",nofdone) + end + end + end + end + if nofdone % 25 ~= 0 then + report_svg("%i shapes submitted",nofdone) + end + report_svg("processing can be going on for a while") + inkscape:write("quit\n") + inkscape:close() + report_svg("processing %i pdf results",nofshapes) + for index in next, processed do + local svgfile = f_svgfile(index) + local pdffile = f_pdffile(index) + -- local fntdata = descriptions[indices[index]] + -- local bounds = fntdata and fntdata.boundingbox + local pdfdata = loaddata(pdffile) + if pdfdata and pdfdata ~= "" then + pdfshapes[index] = { + data = pdfdata, + -- x = bounds and bounds[1] or 0, + -- y = bounds and bounds[2] or 0, + } + end + remove(svgfile) + remove(pdffile) + end + local characters = tfmdata.characters + for k, v in next, characters do + local d = descriptions[k] + local i = d.index + if i then + local p = pdfshapes[i] + if p then + local w = d.width + local l = d.boundingbox[1] + local r = d.boundingbox[3] + p.scale = (r - l) / w + p.x = l + end + end + end + if not next(pdfshapes) then + report_svg("there are no converted shapes, fix your setup") + end + statistics.stoptiming() + if statistics.elapsedseconds then + report_svg("svg conversion time %s",statistics.elapsedseconds() or "-") + end + end + return pdfshapes + end + + initializesvg = function(tfmdata,kind,value) -- hm, always value + if value and otf.svgenabled then + local svg = tfmdata.properties.svg + local hash = svg and svg.hash + local timestamp = svg and svg.timestamp + if not hash then + return + end + local pdffile = containers.read(otf.pdfcache,hash) + local pdfshapes = pdffile and pdffile.pdfshapes + if not pdfshapes or pdffile.timestamp ~= timestamp or not next(pdfshapes) then + -- the next test tries to catch errors in generic usage but of course can result + -- in running again and again + local svgfile = containers.read(otf.svgcache,hash) + local svgshapes = svgfile and svgfile.svgshapes + pdfshapes = svgshapes and otfsvg.topdf(svgshapes,tfmdata,otf.pdfcache.writable,hash) or { } + containers.write(otf.pdfcache, hash, { + pdfshapes = pdfshapes, + timestamp = timestamp, + }) + end + pdftovirtual(tfmdata,pdfshapes,"svg") + return true + end + end + + otfregister { + name = "svg", + description = "svg glyphs", + manipulators = { + base = initializesvg, + node = initializesvg, + } + } + +end + +-- This can be done differently e.g. with ffi and gm and we can share code anway. Using +-- batchmode in gm is not faster and as it accumulates we would need to flush all +-- individual shapes. But ... in context lmtx (and maybe the backport) we will use +-- a different and more efficient method anyway. I'm still wondering if I should +-- keep color code in generic. Maybe it should be optional. + +local initializepng do + + local otfpng = otf.png or { } + otf.png = otfpng + otf.pngenabled = true + + local report_png = logs.reporter("fonts","png conversion") + + local loaddata = io.loaddata + local savedata = io.savedata + local remove = os.remove + + local runner = sandbox and sandbox.registerrunner { + name = "otfpng", + program = "gm", + template = "convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log", + -- reporter = report_png, + } + + if not runner then + -- + -- poor mans variant for generic: + -- + runner = function() + return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log") + end + end + + -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from + -- that file but creating thousands of small files is no fun either. + + local files = utilities.files + local openfile = files.open + local closefile = files.close + local setposition = files.setposition + local readstring = files.readstring + + function otfpng.topdf(pngshapes,filename) + if pngshapes and filename then + local pdfshapes = { } + local pngfile = "temp-otf-png-shape.png" + local pdffile = "temp-otf-png-shape.pdf" + local nofdone = 0 + local indices = sortedkeys(pngshapes) -- can be sparse + local nofindices = #indices + report_png("processing %i png containers",nofindices) + statistics.starttiming() + local filehandle = openfile(filename) + for i=1,nofindices do + local index = indices[i] + local entry = pngshapes[index] + -- local data = entry.data -- or placeholder + local offset = entry.o + local size = entry.s + local x = entry.x + local y = entry.y + local data = nil + if offset and size then + setposition(filehandle,offset) + data = readstring(filehandle,size) + savedata(pngfile,data) + runner() + data = loaddata(pdffile) + end + pdfshapes[index] = { +-- x = x ~= 0 and x or nil, +-- y = y ~= 0 and y or nil, + data = data, + } + nofdone = nofdone + 1 + if nofdone % 100 == 0 then + report_png("%i shapes processed",nofdone) + end + end + closefile(filehandle) + report_png("processing %i pdf results",nofindices) + remove(pngfile) + remove(pdffile) + statistics.stoptiming() + if statistics.elapsedseconds then + report_png("png conversion time %s",statistics.elapsedseconds() or "-") + end + return pdfshapes + end + end + + initializepng = function(tfmdata,kind,value) -- hm, always value + if value and otf.pngenabled then + local png = tfmdata.properties.png + local hash = png and png.hash + local timestamp = png and png.timestamp + if not hash then + return + end + local pdffile = containers.read(otf.pdfcache,hash) + local pdfshapes = pdffile and pdffile.pdfshapes + if not pdfshapes or pdffile.timestamp ~= timestamp then + local pngfile = containers.read(otf.pngcache,hash) + local filename = tfmdata.resources.filename + local pngshapes = pngfile and pngfile.pngshapes + pdfshapes = pngshapes and otfpng.topdf(pngshapes,filename) or { } + containers.write(otf.pdfcache, hash, { + pdfshapes = pdfshapes, + timestamp = timestamp, + }) + end + -- + pdftovirtual(tfmdata,pdfshapes,"png") + return true + end + end + + otfregister { + name = "sbix", + description = "sbix glyphs", + manipulators = { + base = initializepng, + node = initializepng, + } + } + + otfregister { + name = "cblc", + description = "cblc glyphs", + manipulators = { + base = initializepng, + node = initializepng, + } + } + +end + +do + + local function initializecolor(tfmdata,kind,value) + if value == "auto" then + return + initializeoverlay(tfmdata,kind,value) or + initializesvg (tfmdata,kind,value) or + initializepng (tfmdata,kind,value) + elseif value == "overlay" then + return initializeoverlay(tfmdata,kind,value) + elseif value == "svg" then + return initializesvg(tfmdata,kind,value) + elseif value == "png" or value == "bitmap" then + return initializepng(tfmdata,kind,value) + else + -- forget about it + end + end + + otfregister { + name = "color", + description = "color glyphs", + manipulators = { + base = initializecolor, + node = initializecolor, + } + } + +end + +-- Old stuff: + +do + + local startactualtext = nil + local stopactualtext = nil + + function otf.getactualtext(s) + if not startactualtext then + startactualtext = backends.codeinjections.startunicodetoactualtextdirect + stopactualtext = backends.codeinjections.stopunicodetoactualtextdirect + end + return startactualtext(s), stopactualtext() + end + +end + diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index e72605320..bad42054f 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -2084,8 +2084,6 @@ local function readtable(tag,f,fontdata,specification,...) end end -local variablefonts_supported = (context and true) or (logs and logs.application and true) or false - local function readdata(f,offset,specification) local fontdata, tables = loadtables(f,specification,offset) @@ -2094,12 +2092,6 @@ local function readdata(f,offset,specification) prepareglyps(fontdata) end - if not variablefonts_supported then - specification.instance = nil - specification.variable = nil - specification.factors = nil - end - fontdata.temporary = { } readtable("name",f,fontdata,specification) @@ -2118,71 +2110,66 @@ local function readdata(f,offset,specification) readtable("avar",f,fontdata,specification) readtable("fvar",f,fontdata,specification) - if variablefonts_supported then - - local variabledata = fontdata.variabledata - - if variabledata then - local instances = variabledata.instances - local axis = variabledata.axis - if axis and (not instances or #instances == 0) then - instances = { } - variabledata.instances = instances - local function add(n,subfamily,value) - local values = { } - for i=1,#axis do - local a = axis[i] - values[i] = { - axis = a.tag, - value = i == n and value or a.default, - } - end - instances[#instances+1] = { - subfamily = subfamily, - values = values, - } - end + local variabledata = fontdata.variabledata + + if variabledata then + local instances = variabledata.instances + local axis = variabledata.axis + if axis and (not instances or #instances == 0) then + instances = { } + variabledata.instances = instances + local function add(n,subfamily,value) + local values = { } for i=1,#axis do - local a = axis[i] - local tag = a.tag - add(i,"default"..tag,a.default) - add(i,"minimum"..tag,a.minimum) - add(i,"maximum"..tag,a.maximum) + local a = axis[i] + values[i] = { + axis = a.tag, + value = i == n and value or a.default, + } end - -- report("%i fake instances added",#instances) + instances[#instances+1] = { + subfamily = subfamily, + values = values, + } end - end - - if not specification.factors then - local instance = specification.instance - if type(instance) == "string" then - local factors = helpers.getfactors(fontdata,instance) - if factors then - specification.factors = factors - fontdata.factors = factors - fontdata.instance = instance - report("user instance: %s, factors: % t",instance,factors) - else - report("user instance: %s, bad factors",instance) - end + for i=1,#axis do + local a = axis[i] + local tag = a.tag + add(i,"default"..tag,a.default) + add(i,"minimum"..tag,a.minimum) + add(i,"maximum"..tag,a.maximum) end + -- report("%i fake instances added",#instances) end - - if not fontdata.factors then - if fontdata.variabledata then - local factors = helpers.getfactors(fontdata,true) - if factors then - specification.factors = factors - fontdata.factors = factors - -- report("factors: % t",factors) - -- else - -- report("bad factors") - end + end + if not specification.factors then + local instance = specification.instance + if type(instance) == "string" then + local factors = helpers.getfactors(fontdata,instance) + if factors then + specification.factors = factors + fontdata.factors = factors + fontdata.instance = instance + report("user instance: %s, factors: % t",instance,factors) else - -- report("unknown instance") + report("user instance: %s, bad factors",instance) end end + end + if not fontdata.factors then + if fontdata.variabledata then + local factors = helpers.getfactors(fontdata,true) + if factors then + specification.factors = factors + fontdata.factors = factors + -- report("factors: % t",factors) + -- else + -- report("bad factors") + end + else + -- report("unknown instance") + end end readtable("os/2",f,fontdata,specification) diff --git a/tex/context/base/mkiv/font-ott.lua b/tex/context/base/mkiv/font-ott.lua index c9e467f22..f4d7e05a1 100644 --- a/tex/context/base/mkiv/font-ott.lua +++ b/tex/context/base/mkiv/font-ott.lua @@ -1117,41 +1117,6 @@ local checkers = { end } --- Keep this: --- --- function otf.features.normalize(features) --- if features then --- local h = { } --- for k, v in next, features do --- k = lower(k) --- if k == "language" then --- v = gsub(lower(v),"[^a-z0-9]","") --- h.language = rawget(verboselanguages,v) or (languages[v] and v) or "dflt" -- auto adds --- elseif k == "script" then --- v = gsub(lower(v),"[^a-z0-9]","") --- h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds --- else --- if type(v) == "string" then --- local b = is_boolean(v) --- if type(b) == "nil" then --- v = tonumber(v) or lower(v) --- else --- v = b --- end --- end --- if not rawget(features,k) then --- k = rawget(verbosefeatures,k) or k --- end --- local c = checkers[k] --- h[k] = c and c(v) or v --- end --- end --- return h --- end --- end - --- inspect(fonts.handlers.otf.statistics.usedfeatures) - if not storage then return end @@ -1178,9 +1143,6 @@ function otffeatures.normalize(features,wrap) -- wrap is for context h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds elseif k == "axis" then h[k] = normalizedaxis(value) - if not callbacks.supported.glyph_stream_provider then - h.variableshapes = true -- for the moment - end else local uk = usedfeatures[key] local uv = uk[value] diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 4d5254760..c3fea6d46 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -379,124 +379,17 @@ otf.loadstreamdata = loadstreamdata -- not public otf.loadshapes = loadshapes otf.getstreamhash = getstreamhash -- not public, might move to other namespace -local f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"] -local f_l = formatters["%.6N %.6N l"] -local f_m = formatters["%.6N %.6N m"] - -local function segmentstopdf(segments,factor,bt,et) - local t = { } - local m = 0 - local n = #segments - local d = false - for i=1,n do - local s = segments[i] - local w = s[#s] - if w == "c" then - m = m + 1 - t[m] = f_c(s[1]*factor,s[2]*factor,s[3]*factor,s[4]*factor,s[5]*factor,s[6]*factor) - elseif w == "l" then - m = m + 1 - t[m] = f_l(s[1]*factor,s[2]*factor) - elseif w == "m" then - m = m + 1 - t[m] = f_m(s[1]*factor,s[2]*factor) - elseif w == "q" then - local p = segments[i-1] - local n = #p - local l_x = factor*p[n-2] - local l_y = factor*p[n-1] - local m_x = factor*s[1] - local m_y = factor*s[2] - local r_x = factor*s[3] - local r_y = factor*s[4] - m = m + 1 - t[m] = f_c ( - l_x + 2/3 * (m_x-l_x), l_y + 2/3 * (m_y-l_y), - r_x + 2/3 * (m_x-r_x), r_y + 2/3 * (m_y-r_y), - r_x, r_y - ) - end - end - m = m + 1 - t[m] = "h f" -- B* - if bt and et then - t[0] = bt - t[m+1] = et - return concat(t,"\n",0,m+1) - else - return concat(t,"\n") - end -end - -local function initialize(tfmdata,key,value) - if value then - local shapes = otf.loadoutlinedata(tfmdata) - if not shapes then - return - end - local glyphs = shapes.glyphs - if not glyphs then - return - end - local characters = tfmdata.characters - local parameters = tfmdata.parameters - local hfactor = parameters.hfactor * (7200/7227) - local factor = hfactor / 65536 - local getactualtext = otf.getactualtext - for unicode, char in next, characters do - if char.commands then - -- can't happen as we're doing this before other messing around - else - local shape = glyphs[char.index] - if shape then - local segments = shape.segments - if segments then - -- we need inline in order to support color - local bt, et = getactualtext(char.tounicode or char.unicode or unicode) - char.commands = { - { "pdf", "origin", segmentstopdf(segments,factor,bt,et) } - } - end - end - end - end - end -end - -otf.features.register { - name = "variableshapes", -- enforced for now - description = "variable shapes", - manipulators = { - base = initialize, - node = initialize, - } -} - --- In the end it is easier to just provide the new charstring (cff) and points (ttf). First --- of all we already have the right information so there is no need to patch the already complex --- backend code (we only need to make sure the cff is valid). Also, I prototyped support for --- these fonts using (converted to) normal postscript shapes, a functionality that was already --- present for a while for metafun. This solution even permits us to come up with usage of such --- fonts in unexpected ways. It also opens the road to shapes generated with metafun includes --- as real cff (or ttf) shapes instead of virtual in-line shapes. --- --- This is probably a prelude to writing a complete backend font inclusion plugin in lua. After --- all I already have most info. For this we just need to pass a list of used glyphs (or analyze --- them ourselves). - local streams = fonts.hashes.streams -if callbacks.supported.glyph_stream_provider then +-- we can now assume that luatex has this one - callback.register("glyph_stream_provider",function(id,index,mode) - if id > 0 then - local streams = streams[id].streams - -- print(id,index,streams[index]) - if streams then - return streams[index] or "" - end +callback.register("glyph_stream_provider",function(id,index,mode) + if id > 0 then + local streams = streams[id].streams + -- print(id,index,streams[index]) + if streams then + return streams[index] or "" end - return "" - end) - -end + end + return "" +end) diff --git a/tex/context/base/mkiv/grph-con.lua b/tex/context/base/mkiv/grph-con.lua index c3c711b0c..b3d39f0bd 100644 --- a/tex/context/base/mkiv/grph-con.lua +++ b/tex/context/base/mkiv/grph-con.lua @@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['grph-con'] = { local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match local tonumber = tonumber +local find = string.find local longtostring = string.longtostring local formatters = string.formatters local expandfilename = dir.expandname @@ -194,6 +195,22 @@ do -- svg -- arguments change again? Ok, it's weirder, with -A then it's a name only when -- not . (current) + -- Beware: the order of printed output lines is a bit random depending on the + -- method of calling (bin or pipe) because part of the message prints to stdout + -- and part to stderr. Also, on Windows, a second call to the old binaries + -- doesn't return anything at all, so that is also a signal of it being old. + -- This test will be dropped in 2021 anyway. + + local new = nil + + local function inkscapeformat(suffix) + if new == nil then + new = os.resultof("inkscape --version") or "" + new = new == "" or not find(new,"Inkscape%s*0") + end + return new and "filename" or suffix + end + local runner = sandbox.registerrunner { name = "svg to something", program = "inkscape", @@ -209,7 +226,7 @@ do -- svg resolution = "string", }, defaults = { - format = "pdf", + format = format, resolution = "600", } } @@ -220,7 +237,7 @@ do -- svg function svgconverter.pdf(oldname,newname) runner { - format = "pdf", + format = inkscapeformat("pdf"), resolution = "600", newname = expandfilename(newname), oldname = expandfilename(oldname), @@ -229,7 +246,7 @@ do -- svg function svgconverter.png(oldname,newname) runner { - format = "png", + format = inkscapeformat("png"), resolution = "600", newname = expandfilename(newname), oldname = expandfilename(oldname), diff --git a/tex/context/base/mkiv/grph-trf.lua b/tex/context/base/mkiv/grph-trf.lua new file mode 100644 index 000000000..f476ec692 --- /dev/null +++ b/tex/context/base/mkiv/grph-trf.lua @@ -0,0 +1,125 @@ +if not modules then modules = { } end modules ['grph-trf'] = { + version = 1.001, + comment = "companion to grph-trf.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- see grph-trf-todo.lua for older preliminary code for the rest + +local sind, cosd, tand, abs = math.sind, math.cosd, math.tand, math.abs + +local texsetdimen = tex.setdimen + +local function analyzerotate(rotation,width,height,depth,total,notfit,obeydepth) + -- + -- print(rotation,width,height,depth,notfit,obeydepth) + -- + local sin = sind(rotation) + local cos = cosd(rotation) + local abssin = abs(sin) + local abscos = abs(cos) + local xsize = 0 + local ysize = 0 + local xposition = 0 + local yposition = 0 + local xoffset = 0 + local yoffset = 0 + local newwidth = width + local newheight = height + local newdepth = depth + -- print(sin,cos) + if sin > 0 then + if cos > 0 then + xsize = cos * width + sin * total + ysize = sin * width + cos * total + yposition = cos * total + if notfit then + xoffset = - sin * height + newwidth = sin * depth + cos * width + else + newwidth = xsize + xposition - xoffset + end + if obeydepth then + yoffset = cos * depth + end + newheight = ysize - yoffset + newdepth = yoffset + -- print("case 1, done") + else + xsize = abscos * width + sin * total + ysize = sin * width + abscos * total + xposition = abscos * width + if notfit then + xoffset = - xsize + sin * depth + end + if obeydepth then + yoffset = abscos * height + newwidth = abssin * total + abscos * width + xoffset + else + newwidth = xsize + end + newheight = ysize - yoffset + newdepth = yoffset + -- print("case 2, done") + end + else + if cos < 0 then + xsize = abscos * width + abssin * total + ysize = abssin * width + abscos * total + xposition = xsize + yposition = abssin * width + if notfit then + xoffset = - xsize + abssin * height + end + if obeydepth then + yoffset = ysize + cos * depth + end + newwidth = notfit and (abssin * height) or xsize + newheight = ysize - yoffset + newdepth = yoffset + -- print("case 3, done") + else + xsize = cos * width + abssin * total + ysize = abssin * width + cos * total + xposition = abssin * total + yposition = cos * total + if notfit then + xoffset = - abssin * depth + newwidth = xsize + xoffset + else + newwidth = xsize + end + if obeydepth then + yoffset = cos * depth + end + newheight = ysize - yoffset + sin * width + newdepth = yoffset - sin * width + -- print("case 4, done") + end + end + texsetdimen("d_grph_rotate_x_size", xsize) + texsetdimen("d_grph_rotate_y_size", ysize) + texsetdimen("d_grph_rotate_x_position", xposition) + texsetdimen("d_grph_rotate_y_position", yposition) + texsetdimen("d_grph_rotate_x_offset", xoffset) + texsetdimen("d_grph_rotate_y_offset", yoffset) + texsetdimen("d_grph_rotate_new_width", newwidth) + texsetdimen("d_grph_rotate_new_height", newheight) + texsetdimen("d_grph_rotate_new_depth", newdepth) +end + +interfaces.implement { + name = "analyzerotate", + actions = analyzerotate, + arguments = { + "integer", + "dimension", + "dimension", + "dimension", + "dimension", + "conditional", + "conditional", + }, +} diff --git a/tex/context/base/mkiv/grph-trf.mkiv b/tex/context/base/mkiv/grph-trf.mkiv index f9218036c..522dd08d6 100644 --- a/tex/context/base/mkiv/grph-trf.mkiv +++ b/tex/context/base/mkiv/grph-trf.mkiv @@ -24,6 +24,8 @@ %D We could move the calculations to \LUA\ and clean up this lot anyway. On the %D other hand, there is some danger of messing up so it has a real low priority. +\registerctxluafile{grph-trf}{} + % local: \newdimen\d_grph_scale_x_size @@ -794,6 +796,8 @@ \installcorenamespace {rotatelocation} \installcorenamespace {rotatepreset} +% todo: scratchcounters + \newdimen\d_grph_rotate_x_size \newdimen\d_grph_rotate_y_size \newdimen\d_grph_rotate_x_offset @@ -811,6 +815,10 @@ \let\d_grph_rotate_saved_height\!!heightb \let\d_grph_rotate_saved_depth \!!depthb +\let\d_grph_rotate_new_width \!!widthc +\let\d_grph_rotate_new_height\!!heightc +\let\d_grph_rotate_new_depth \!!depthc + \newconditional\c_grph_rotate_obey_depth \newconditional\c_grph_rotate_not_fit \newconditional\c_grph_rotate_center @@ -948,111 +956,30 @@ \d_grph_rotate_saved_width \wd\nextbox \d_grph_rotate_saved_height\ht\nextbox \d_grph_rotate_saved_depth \dp\nextbox - \setbox\nextbox\naturalvpack{\vskip.5\ht\nextbox\hskip-.5\wd\nextbox\box\nextbox}% + \setbox\nextbox\naturalhpack{\hskip-.5\wd\nextbox\lower.5\ht\nextbox\box\nextbox}% \smashbox\nextbox \fi + % \d_grph_rotate_width \wd\nextbox \d_grph_rotate_height\ht\nextbox \d_grph_rotate_depth \dp\nextbox - \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}% - \d_grph_rotate_used_height \ht\nextbox - % much of the next happens in lua (all the sin and cos) so we can do that in - % one go if needed - \setcalculatedcos\cos\p_rotation_rotation - \setcalculatedsin\sin\p_rotation_rotation - \ifdim\sin\points>\zeropoint - \ifdim\cos\points>\zeropoint - \grph_rotate_calculate_a - \grph_rotate_apply - \else - \grph_rotate_calculate_b - \grph_rotate_apply - \wd\nextbox\ifconditional\c_grph_rotate_not_fit\sin\d_grph_rotate_depth\else\d_grph_rotate_x_size\fi - \fi - \else - \ifdim\cos\points<\zeropoint - \grph_rotate_calculate_c - \grph_rotate_apply - \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi - \else\ifdim\sin\points=\zeropoint - \grph_rotate_calculate_d - \grph_rotate_apply - % no wd ? - \else - \grph_rotate_calculate_e - \grph_rotate_apply - \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi - \fi\fi - \fi - \ifconditional\c_grph_rotate_center - \setbox\nextbox\naturalvpack{\vskip-.5\d_grph_rotate_saved_height\hskip.5\d_grph_rotate_saved_height\box\nextbox}% - \wd\nextbox\d_grph_rotate_saved_width - \ht\nextbox\d_grph_rotate_saved_height - \dp\nextbox\d_grph_rotate_saved_depth - \fi - \boxcursor\box\nextbox} - -\def\grph_rotate_calculate_a - {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax - \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax - \d_grph_rotate_x_position\zeropoint - \d_grph_rotate_y_position\cos\d_grph_rotate_used_height - \ifconditional\c_grph_rotate_not_fit - \d_grph_rotate_x_offset\dimexpr\negated\sin\d_grph_rotate_used_height+\sin\d_grph_rotate_depth\relax - \fi - \ifconditional\c_grph_rotate_obey_depth - \d_grph_rotate_y_offset\cos\d_grph_rotate_depth - \fi} - -\def\grph_rotate_calculate_b - {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax - \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax - \d_grph_rotate_x_position\negated\cos\d_grph_rotate_width - \d_grph_rotate_y_position\zeropoint - \ifconditional\c_grph_rotate_not_fit - \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\sin\d_grph_rotate_depth\relax - \fi - \ifconditional\c_grph_rotate_obey_depth - \d_grph_rotate_y_offset\negated\cos\d_grph_rotate_height - \fi} - -\def\grph_rotate_calculate_c - {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax - \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax - \d_grph_rotate_x_position\d_grph_rotate_x_size - \d_grph_rotate_y_position\negated\sin\d_grph_rotate_width - \ifconditional\c_grph_rotate_not_fit - \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax - \fi - \ifconditional\c_grph_rotate_obey_depth - \d_grph_rotate_y_offset\dimexpr\d_grph_rotate_y_size+\cos\d_grph_rotate_depth\relax - \fi} - -\def\grph_rotate_calculate_d - {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax - \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax - \d_grph_rotate_x_position\zeropoint - \d_grph_rotate_y_position\d_grph_rotate_y_size - \d_grph_rotate_x_offset\zeropoint - \ifconditional\c_grph_rotate_obey_depth - \d_grph_rotate_y_offset\d_grph_rotate_depth - \fi} - -\def\grph_rotate_calculate_e - {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax - \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax - \d_grph_rotate_x_position\negated\sin\d_grph_rotate_used_height - \d_grph_rotate_y_position\d_grph_rotate_y_size - \ifconditional\c_grph_rotate_not_fit - \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax - \fi - \ifconditional\c_grph_rotate_obey_depth - \d_grph_rotate_y_offset\negated\sin\d_grph_rotate_depth - \fi} - -\def\grph_rotate_apply - {\setbox\nextbox\naturalvpack to \d_grph_rotate_y_size - {\vfill + % + \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}% can we do without + % + \d_grph_rotate_used_height\ht\nextbox + % + \clf_analyzerotate % rather accurate + \numexpr\p_rotation_rotation\relax + \d_grph_rotate_width + \d_grph_rotate_height + \d_grph_rotate_depth + \d_grph_rotate_used_height + \c_grph_rotate_not_fit + \c_grph_rotate_obey_depth + \relax + % + \setbox\nextbox\naturalvpack to \d_grph_rotate_y_size + {\vfilll \naturalhpack to \d_grph_rotate_x_size {\dostartrotation\p_rotation_rotation \wd\nextbox\zeropoint @@ -1061,9 +988,24 @@ \dostoprotation \hfill}% \kern\d_grph_rotate_y_position}% + % \setbox\nextbox\naturalhpack {\kern\dimexpr\d_grph_rotate_x_position+\d_grph_rotate_x_offset\relax - \lower\d_grph_rotate_y_offset\box\nextbox}} + \lower\d_grph_rotate_y_offset + \box\nextbox}% + % + \ifconditional\c_grph_rotate_center + \setbox\nextbox\naturalhpack{\hskip.5\d_grph_rotate_saved_width\lower-.5\d_grph_rotate_saved_height\box\nextbox}% + \wd\nextbox\d_grph_rotate_saved_width + \ht\nextbox\d_grph_rotate_saved_height + \dp\nextbox\d_grph_rotate_saved_depth + \else + \wd\nextbox\d_grph_rotate_new_width + \ht\nextbox\d_grph_rotate_new_height + \dp\nextbox\d_grph_rotate_new_depth + \fi + % + \boxcursor\box\nextbox} % \dostepwiserecurse{0}{360}{10} % {\startlinecorrection[blank] @@ -1077,4 +1019,23 @@ % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}} % \stoplinecorrection} +% \def\Test{\ruledhbox{% +% \def\DemoX{\vl\kern.5\emwidth\vl}% +% \kern\emwidth\ruledhpack{\green\rotate[rotation=20] {\ruledhpack{\DemoX}}}% +% \kern\emwidth\ruledhpack{\blue \rotate[rotation=0] {\ruledhpack{\DemoX}}}% +% \kern\emwidth\ruledhpack{\red \rotate[rotation=-20] {\ruledhpack{\DemoX}}}% +% \kern\emwidth\ruledhpack{\green\rotate[rotation=200] {\ruledhpack{\DemoX}}}% +% \kern\emwidth\ruledhpack{\blue \rotate[rotation=180] {\ruledhpack{\DemoX}}}% +% \kern\emwidth\ruledhpack{\red \rotate[rotation=-200]{\ruledhpack{\DemoX}}}% +% \kern\emwidth}} + +% \startTEXpage[offset=10pt,align=middle] +% \setuprotate[location=fit] \Test \par {\infofont\setstrut\strut fit} \par +% \setuprotate[location=depth] \Test \par {\infofont\setstrut\strut depth} \par +% \setuprotate[location=broad] \Test \par {\infofont\setstrut\strut broad} \par +% \setuprotate[location=high] \Test \par {\infofont\setstrut\strut high} \par +% \setuprotate[location=middle] \Test \par {\infofont\setstrut\strut middle} \par +% \setuprotate[location=default] \Test \par {\infofont\setstrut\strut default} \par +% \stopTEXpage + \protect \endinput diff --git a/tex/context/base/mkiv/lpdf-lmt.lua b/tex/context/base/mkiv/lpdf-lmt.lua index 8148bec01..ab07e984d 100644 --- a/tex/context/base/mkiv/lpdf-lmt.lua +++ b/tex/context/base/mkiv/lpdf-lmt.lua @@ -2228,20 +2228,22 @@ local openfile, closefile do closefile = function(abort) if abort then f:close() - f = io.open(abort,"wb") - if f then - local name = resolvers.findfile("context-lmtx-error.pdf") - if name then - local data = io.loaddata(name) - if data then - f:write(data) - f:close() - return + if not environment.arguments.nodummy then + f = io.open(abort,"wb") + if f then + local name = resolvers.findfile("context-lmtx-error.pdf") + if name then + local data = io.loaddata(name) + if data then + f:write(data) + f:close() + return + end end + f:close() end - f:close() - removefile(abort) end + removefile(abort) else local xrefoffset = offset local lastfree = 0 diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv index ca92476ed..c419e39ee 100644 --- a/tex/context/base/mkiv/math-ini.mkiv +++ b/tex/context/base/mkiv/math-ini.mkiv @@ -103,9 +103,9 @@ \def\Umathaccents {\Umathaccent \s!both } \ifdefined\Umathcharclass \else - \def\Umathcharclass{\cldcontext{tex.getmathcode(token.scan_int())[1]}} - \def\Umathcharfam {\cldcontext{tex.getmathcode(token.scan_int())[2]}} - \def\Umathcharslot {\cldcontext{tex.getmathcode(token.scan_int())[3]}} + \def\Umathcharclass{\numexpr\cldcontext{tex.getmathcode(token.scan_int())[1]}\relax} + \def\Umathcharfam {\numexpr\cldcontext{tex.getmathcode(token.scan_int())[2]}\relax} + \def\Umathcharslot {\numexpr\cldcontext{tex.getmathcode(token.scan_int())[3]}\relax} \fi %D The attributes that we will use (todo: pack some into one but uglier code): @@ -2924,6 +2924,71 @@ \let\unstackscripts\math_scripts_unstack \to \everymathematics +%D Expensive (tracing and inject) but a primitive (using factors) is tricky as we +%D want this frozen support. + +\ifcase\contextlmtxmode + + \def\math_openup_parameter#1#2% + {\ifzeropt#1\displaystyle \else\ifdim#1\displaystyle =\maxdimen\else\frozen#1\displaystyle #2#1\displaystyle \fi\fi + \ifzeropt#1\crampeddisplaystyle \else\ifdim#1\crampeddisplaystyle =\maxdimen\else\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi\fi + \ifzeropt#1\textstyle \else\ifdim#1\textstyle =\maxdimen\else\frozen#1\textstyle #2#1\textstyle \fi\fi + \ifzeropt#1\crampedtextstyle \else\ifdim#1\crampedtextstyle =\maxdimen\else\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi\fi + \ifzeropt#1\scriptstyle \else\ifdim#1\scriptstyle =\maxdimen\else\frozen#1\scriptstyle #2#1\scriptstyle \fi\fi + \ifzeropt#1\crampedscriptstyle \else\ifdim#1\crampedscriptstyle =\maxdimen\else\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi\fi + \ifzeropt#1\scriptscriptstyle \else\ifdim#1\scriptscriptstyle =\maxdimen\else\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi\fi + \ifzeropt#1\crampedscriptscriptstyle\else\ifdim#1\crampedscriptscriptstyle=\maxdimen\else\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi\fi} + +\else + + % \def\math_openup_parameter#1#2% + % {\ifzeropt#1\displaystyle \orelse\ifdim#1\displaystyle =\maxdimen\else\frozen#1\displaystyle #2#1\displaystyle \fi + % \ifzeropt#1\crampeddisplaystyle \orelse\ifdim#1\crampeddisplaystyle =\maxdimen\else\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi + % \ifzeropt#1\textstyle \orelse\ifdim#1\textstyle =\maxdimen\else\frozen#1\textstyle #2#1\textstyle \fi + % \ifzeropt#1\crampedtextstyle \orelse\ifdim#1\crampedtextstyle =\maxdimen\else\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi + % \ifzeropt#1\scriptstyle \orelse\ifdim#1\scriptstyle =\maxdimen\else\frozen#1\scriptstyle #2#1\scriptstyle \fi + % \ifzeropt#1\crampedscriptstyle \orelse\ifdim#1\crampedscriptstyle =\maxdimen\else\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi + % \ifzeropt#1\scriptscriptstyle \orelse\ifdim#1\scriptscriptstyle =\maxdimen\else\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi + % \ifzeropt#1\crampedscriptscriptstyle\orelse\ifdim#1\crampedscriptscriptstyle=\maxdimen\else\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi} + + % \def\mdim#1#2% + % {\ifcase\ifzeropt#1#2\plusone\orelse\ifdim#1#2=\maxdimen\plusone\else\zerocount\fi} + % + % \def\mdim + % {\afterassignment\mmdim\scratchdimen} + % + % \def\mmdim + % {\ifcase\ifzeropt\scratchdimen\plusone\orelse\ifdim\scratchdimen=\maxdimen\plusone\else\zerocount\fi} + % + % \def\math_openup_parameter#1#2% + % {\ifcondition\mdim#1\displaystyle \frozen#1\displaystyle #2\dimexpr#1\displaystyle \relax\fi + % \ifcondition\mdim#1\crampeddisplaystyle \frozen#1\crampeddisplaystyle #2\dimexpr#1\crampeddisplaystyle \relax\fi + % \ifcondition\mdim#1\textstyle \frozen#1\textstyle #2\dimexpr#1\textstyle \relax\fi + % \ifcondition\mdim#1\crampedtextstyle \frozen#1\crampedtextstyle #2\dimexpr#1\crampedtextstyle \relax\fi + % \ifcondition\mdim#1\scriptstyle \frozen#1\scriptstyle #2\dimexpr#1\scriptstyle \relax\fi + % \ifcondition\mdim#1\crampedscriptstyle \frozen#1\crampedscriptstyle #2\dimexpr#1\crampedscriptstyle \relax\fi + % \ifcondition\mdim#1\scriptscriptstyle \frozen#1\scriptscriptstyle #2\dimexpr#1\scriptscriptstyle \relax\fi + % \ifcondition\mdim#1\crampedscriptscriptstyle\frozen#1\crampedscriptscriptstyle#2\dimexpr#1\crampedscriptscriptstyle\relax\fi} + + % \Umathparameter : 0=zero, 1=set, 2=unset (les stracing clutter this way) + + \def\math_openup_parameter#1#2% + {\ifcase\Umathparameter#1\displaystyle \or\frozen#1\displaystyle #2#1\displaystyle \fi + \ifcase\Umathparameter#1\crampeddisplaystyle \or\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi + \ifcase\Umathparameter#1\textstyle \or\frozen#1\textstyle #2#1\textstyle \fi + \ifcase\Umathparameter#1\crampedtextstyle \or\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi + \ifcase\Umathparameter#1\scriptstyle \or\frozen#1\scriptstyle #2#1\scriptstyle \fi + \ifcase\Umathparameter#1\crampedscriptstyle \or\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi + \ifcase\Umathparameter#1\scriptscriptstyle \or\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi + \ifcase\Umathparameter#1\crampedscriptscriptstyle\or\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi} + +\fi + +\unexpanded\def\mathopenupparameter#1#2% + {\ifdim#2\points=\zeropoint\else + \math_openup_parameter#1{#2}% + \fi} + \protect \endinput % % not used (yet) diff --git a/tex/context/base/mkiv/math-rad.mkvi b/tex/context/base/mkiv/math-rad.mkvi index c0b128a61..c640e768e 100644 --- a/tex/context/base/mkiv/math-rad.mkvi +++ b/tex/context/base/mkiv/math-rad.mkvi @@ -43,8 +43,36 @@ % \let\normalsurd\surd % \Uradical "0 "221A % \unexpanded\def\surd{\normalsurd{}} - -%D The real thing: +%D The real thing. If needed one can control matters with one of the many +%D \type {\Umath...} parameters. +%D +%D \starttyping +%D \def\R {\Umathradicaldegreeafter\textstyle0pt} +%D \def\RR{\Umathradicaldegreeafter\textstyle\dimexpr +%D \Umathradicaldegreeafter\textstyle+.1em\relax} +%D \def\RRR{\frozen\Umathradicaldegreeafter\textstyle\dimexpr +%D \Umathradicaldegreeafter\textstyle+.2em\relax} +%D +%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par +%D $ \sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par +%D $ \RR\sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par +%D +%D \def\R {\Umathradicaldegreeafter\textstyle +%D 0pt} +%D \def\RR {\Umathradicaldegreeafter\textstyle +%D 0.95\Umathradicaldegreeafter\textstyle} +%D \def\RRR{\frozen\Umathradicaldegreeafter\textstyle +%D 0.9\Umathradicaldegreeafter\textstyle} +%D +%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par +%D $ \sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par +%D $ \RR\sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par +%D +%D \def\RR {\mathopenupparameter\Umathradicaldegreeafter{.1}} +%D +%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par +%D $ \sqrt[3]{5} {\RR\sqrt[3]{5}} \sqrt[3]{5} $\par +%D \stoptyping \installcorenamespace{mathradical} \installcorenamespace{mathradicalalternative} diff --git a/tex/context/base/mkiv/mlib-ctx.mkxl b/tex/context/base/mkiv/mlib-ctx.mkxl index bb2460627..dd2d0ae24 100644 --- a/tex/context/base/mkiv/mlib-ctx.mkxl +++ b/tex/context/base/mkiv/mlib-ctx.mkxl @@ -18,6 +18,7 @@ \registerctxluafile{mlib-lua}{} \registerctxluafile{mlib-scn}{} \registerctxluafile{mlib-mat}{} +\registerctxluafile{mlib-ran}{} \registerctxluafile{mlib-lmp}{} \registerctxluafile{mlib-int}{} \registerctxluafile{mlib-lmt}{} diff --git a/tex/context/base/mkiv/mlib-ran.lua b/tex/context/base/mkiv/mlib-ran.lua new file mode 100644 index 000000000..cb8645e8d --- /dev/null +++ b/tex/context/base/mkiv/mlib-ran.lua @@ -0,0 +1,237 @@ +if not modules then modules = { } end modules ['mlib-ran'] = { + version = 1.001, + comment = "companion to mlib-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +local next = next +local ceil, floor, random, sqrt, cos, sin, pi, max, min = math.ceil, math.floor, math.random, math.sqrt, math.cos, math.sin, math.pi, math.min, math.max +local remove = table.remove + +-- Below is a bit of rainy saturday afternoon hobyism, while listening to Judith +-- Owens redisCOVERed (came there via Leland Sklar who I have on a few live blurays; +-- and who is also on YT). (Also nice: https://www.youtube.com/watch?v=GXqasIRaxlA) + +-- When Aditya pointed me to an article on mazes I ended up at poison distributions +-- which to me looks nicer than what I normally do, fill a grid and then randomize +-- the resulting positions. With some hooks this can be used for interesting patterns +-- too. A few links: +-- +-- https://bost.ocks.org/mike/algorithms/#maze-generation +-- https://extremelearning.com.au/ +-- https://www.jasondavies.com/maps/random-points/ +-- http://devmag.org.za/2009/05/03/poisson-disk-sampling + +-- The next function is quite close to what us discribed in the poisson-disk-sampling +-- link mentioned before. One can either use a one dimensional grid array or a two +-- dimensional one. The example code uses some classes dealing with points. In the +-- process I added some more control. + +-- we could do without the samplepoints list + +local function poisson(width, height, mindist, newpointscount, initialx, initialy) + local starttime = os.clock() + local cellsize = mindist / sqrt(2) + local nofwidth = ceil(width // cellsize) + local nofheight = ceil(height // cellsize) + local grid = lua.newtable(nofwidth,0) -- table.setmetatableindex("table") + local firstx = initialx or random() * width + local firsty = initialy or random() * height + local firstpoint = { firstx, firsty, 1 } + -- local samplepoints = { firstpoint } + local processlist = { firstpoint } + local nofprocesslist = 1 + local nofsamplepoints = 1 + local twopi = 2 * pi + + for i=1,nofwidth do + local g = lua.newindex(nofheight,false) + grid[i] = g + end + + local x = floor(firstx // cellsize) + 1 -- lua indices + local y = floor(firsty // cellsize) + 1 -- lua indices + + x = max(1, min(x, width - 1)) + y = max(1, min(y, height - 1)) + + grid[x][y] = firstpoint + + -- The website shows graphic for this 5*5 grid snippet, if we use a one dimentional + -- array then we could have one loop; a first version used a metatable trick so we + -- had grid[i+gx][j+gy] but we no we also return the grid, so ... we now just check. + + -- There is no need for the samplepoints list as we can get that from the grid but + -- instead we can store the index with the grid. + + while nofprocesslist > 0 do + local point = remove(processlist,random(1,nofprocesslist)) + nofprocesslist = nofprocesslist - 1 + for i=1,newpointscount do -- we start at 1 + local radius = mindist * (random() + 1) + local angle = twopi * random() + local nx = point[1] + radius * cos(angle) + local ny = point[2] + radius * sin(angle) + if nx > 1 and ny > 1 and nx <= width and ny <= height then -- lua indices + local gx = floor(nx // cellsize) + local gy = floor(ny // cellsize) + -- the 5x5 cells around the point + for i=-2,2 do + for j=-2,2 do + local cell = grid[i + gx] + if cell then + cell = cell[j + gy] + if cell and sqrt((cell[1] - nx)^2 + (cell[2] - ny)^2) < mindist then + goto next + end + end + end + end + -- local newpoint = { nx, ny } + nofprocesslist = nofprocesslist + 1 + nofsamplepoints = nofsamplepoints + 1 + local newpoint = { nx, ny, nofsamplepoints } + processlist [nofprocesslist] = newpoint + -- samplepoints[nofsamplepoints] = newpoint + grid[gx][gy] = newpoint + end + ::next:: + end + end + + return { + count = nofsamplepoints, + -- points = samplepoints, + grid = grid, + time = os.clock() - starttime, + } +end + +-- For now: + +local randomizers = utilities.randomizers or { } +utilities.randomizers = randomizers +randomizers.poisson = poisson + +-- The MetaFun interface: + +local formatters = string.formatters +local concat = table.concat + +local f_macro = formatters["%s(%N,%N);"] + +local f_macros = { + [2] = formatters["%s(%N,%N);"], + [3] = formatters["%s(%N,%N,%i);"], + [4] = formatters["%s(%N,%N,%i,%i);"], +} + +function grid_to_mp(t,f,n) + local grid = t.grid + local count = t.count + local result = { } + local r = 0 + local macro = f or "draw" + local runner = f_macros[n or 2] or f_macros[2] + for i=1,#grid do + local g = grid[i] + if g then + for j=1,#g do + local v = g[j] + if v then + r = r + 1 + result[r] = runner(macro,v[1],v[2],v[3],count) + end + end + end + end + return concat(result, " ") +end + +local getparameter = metapost.getparameter + +local function lmt_poisson() + local initialx = getparameter { "initialx" } + local initialy = getparameter { "initialy" } + local width = getparameter { "width" } + local height = getparameter { "height" } + local distance = getparameter { "distance" } + local count = getparameter { "count" } + + local result = poisson ( + width, height, distance, count, + initialx > 0 and initialx or false, + initialy > 0 and initialy or false + ) + + if result then + logs.report("poisson","w=%N, h=%N, d=%N, c=%N, n=%i, runtime %.3f", + width, height, distance, count, result.count, result.time + ) + end + + return result +end + +function mp.lmt_poisson_generate() + local result = lmt_poisson() + if result then + return grid_to_mp ( + result, + getparameter { "macro" }, + getparameter { "arguments" } + ) + end +end + +-- -- some playing around showed no benefit +-- +-- function points_to_mp(t,f) +-- local points = t.points +-- local count = t.count +-- local result = { } +-- local r = 0 +-- local macro = f or "draw" +-- local runner = f_macros[n or 2] or f_macros[2] +-- for i=1,count do +-- local v = points[i] +-- r = r + 1 +-- result[r] = runner(macro,v[1],v[2],v[3],count) +-- end +-- return concat(result, " ") +-- end +-- +-- local result = false +-- local i, j, n = 0, 0, 0 +-- +-- function mp.lmt_poison_start() +-- result = lmt_poisson() +-- end +-- +-- function mp.lmt_poisson_stop() +-- result = false +-- end +-- +-- function mp.lmt_poisson_count() +-- return result and result.count or 0 +-- end +-- +-- function mp.lmt_poisson_get(i) +-- if result then +-- return mp.pair(result.points[i]) +-- end +-- end +-- +-- function mp.lmt_poisson_generate() +-- mp.lmt_poisson_start() +-- if result then +-- return grid_to_mp ( +-- result, +-- getparameter { "macro" }, +-- getparameter { "arguments" } +-- ) +-- end +-- mp.lmt_poisson_stop() +-- end diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 5ff7f6bfc..36a8cd8e5 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -159,6 +159,7 @@ return { "Umathoverbarvgap", "Umathoverdelimiterbgap", "Umathoverdelimitervgap", + "Umathparameter", "Umathpunctbinspacing", "Umathpunctclosespacing", "Umathpunctinnerspacing", @@ -219,6 +220,7 @@ return { "Ustartmath", "Ustopdisplaymath", "Ustopmath", + "Ustyle", "Usubscript", "Usuperscript", "Uunderdelimiter", diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua index 1832a0d1e..9b76fed54 100644 --- a/tex/context/base/mkiv/node-res.lua +++ b/tex/context/base/mkiv/node-res.lua @@ -36,6 +36,7 @@ local glyph_code = nodecodes.glyph local rule_code = nodecodes.rule local kern_code = nodecodes.kern local glue_code = nodecodes.glue +local gluespec_code = nodecodes.gluespec local whatsit_code = nodecodes.whatsit local currentfont = font.current @@ -163,6 +164,7 @@ local fontkern = register_nut(new_nut(kern_code,kerncodes.fontkern)) local italickern = register_nut(new_nut(kern_code,kerncodes.italiccorrection)) local penalty = register_nut(new_nut(nodecodes.penalty)) local glue = register_nut(new_nut(glue_code)) +local gluespec = register_nut(new_nut(gluespec_code)) local glyph = register_nut(new_nut(glyph_code,0)) local textdir = register_nut(new_nut(nodecodes.dir)) @@ -283,6 +285,14 @@ function nutpool.italickern(k) return n end +function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) + local n = copy_nut(gluespec) + if width or stretch or shrink or stretch_order or shrink_order then + setglue(n,width,stretch,shrink,stretch_order,shrink_order) + end + return n +end + local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) -- maybe setglue local n = copy_nut(skip) diff --git a/tex/context/base/mkiv/spac-par.mkiv b/tex/context/base/mkiv/spac-par.mkiv index 7678cc34b..1fd1cbd8a 100644 --- a/tex/context/base/mkiv/spac-par.mkiv +++ b/tex/context/base/mkiv/spac-par.mkiv @@ -15,13 +15,19 @@ \unprotect -%D The dreadful sequence \type {\bgroup} \unknown\ -%D \type {\carryoverpar} \unknown\ \type {\egroup} is needed -%D when for instance sidefloats are used in combination with -%D something that starts with a group. This is because -%D otherwise the indentation as set (by the output routine) -%D inside the group are forgotten afterwards. (I must -%D not forget its existence). +%D The dreadful sequence \type {\bgroup} \unknown\ \type {\carryoverpar} \unknown\ +%D \type {\egroup} is needed when for instance sidefloats are used in combination +%D with something that starts with a group. This is because otherwise the +%D indentation as set (by the output routine) inside the group are forgotten +%D afterwards. (I must not forget its existence). + +% Todo (maybe): +% +% \parshape \getparshape\relax +% \interlinepenalties \getinterlinepenalties\relax +% \clubpenalties \getclubpenalties\relax +% \widowpenalties \getwidowpenalties\relax +% \displaywidowpenalties\getdisplaywidowpenalties\relax \def\carryoverpar#1% #1 can be \endgroup or \egroup or ... expandable ! {\normalexpanded @@ -43,8 +49,8 @@ \unexpanded\def\flushparagraphproperties {\popmacro\currentparagraphproperties} -% Beware, changing this will break some code (like pos/backgrounds) but -% it has been changed anyway so let's see where things go wrong. +%D Beware, changing this will break some code (like pos/backgrounds) but it has been +%D changed anyway so let's see where things go wrong. \installcorenamespace{paragraphintro} @@ -133,11 +139,11 @@ \gtoksapp\t_spac_paragraphs_intro_first{#1}% \glet\insertparagraphintro\spac_paragraphs_flush_intro} -%D Here comes the flusher (we misuse the one level expansion of token -%D registers to feed a nice stream into the paragraph.) +%D Here comes the flusher (we misuse the one level expansion of token registers to +%D feed a nice stream into the paragraph.) -\unexpanded\def\spac_paragraphs_flush_intro % we make sure that the token lists expand directly after another - {\normalexpanded{% % so the first code is there twice +\unexpanded\def\spac_paragraphs_flush_intro % we make sure that the token lists expand directly + {\normalexpanded{% % after another so the first code is there twice \ifconditional\c_spac_paragraphs_intro_each \ifconditional\c_spac_paragraphs_intro_next \glet\insertparagraphintro\spac_paragraphs_flush_intro_next @@ -180,8 +186,8 @@ %D \macros %D {flushatnextpar} %D -%D This macro collects data that will be flushed at the next paragraph. -%D By using this macro you can avoid interfering nodes (writes, etc). +%D This macro collects data that will be flushed at the next paragraph. By using +%D this macro you can avoid interfering nodes (writes, etc). \let\flushpostponednodedata\relax % hook into everypar diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 97606d8ba..2fc104db6 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex 858c331bb..20fc6a9b8 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/supp-ran.lua b/tex/context/base/mkiv/supp-ran.lua index 1a2d10bea..ef2654406 100644 --- a/tex/context/base/mkiv/supp-ran.lua +++ b/tex/context/base/mkiv/supp-ran.lua @@ -132,6 +132,8 @@ utilities.randomizer = { reuseseed = reuserandomseed, popseed = poprandomseed, get = getrandom, + -- the original, only for testing + -- mathrandom = random, } -- todo: also open up in utilities.randomizer.* diff --git a/tex/context/base/mkiv/syst-aux.lua b/tex/context/base/mkiv/syst-aux.lua index 28fcb65fa..e28e23be0 100644 --- a/tex/context/base/mkiv/syst-aux.lua +++ b/tex/context/base/mkiv/syst-aux.lua @@ -11,20 +11,20 @@ if not modules then modules = { } end modules ['syst-aux'] = { -- utfmatch(str,"(.?)(.*)$") -- utf.sub(str,1,1) -local tonumber, next = tonumber, next +local tonumber, next, type = tonumber, next, type local utfsub = utf.sub local P, S, R, C, Cc, Cs, Carg, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match local next = next -local find = string.find +local find, formatters = string.find, string.formatters local context = context local implement = interfaces.implement -local formatters = string.formatters +local setmacro = interfaces.setmacro local setcatcode = tex.setcatcode +local texget = tex.get local utf8character = lpeg.patterns.utf8character local settings_to_array = utilities.parsers.settings_to_array local settings_to_set = utilities.parsers.settings_to_set -local setmacro = interfaces.setmacro local pattern = C(utf8character^-1) * C(P(1)^0) @@ -780,15 +780,58 @@ implement { local bp = number.dimenfactors.bp -interfaces.implement { +implement { name = "tobigpoints", actions = function(d) context("%.5F",bp * d) end, arguments = "dimension", } -interfaces.implement { +implement { name = "towholebigpoints", actions = function(d) context("%r",bp * d) end, arguments = "dimension", } +-- for now here: + +local function getshape(s) + local t = texget(s) + local n = t and #t or 0 + context(n) + if n > 0 then + for i=1,n do + local ti = t[i] + if type(ti) == "table" then + context(" %isp %isp",ti[1],ti[2]) + else + context(" %i",ti) + end + end + end +end + +implement { + name = "getparshape", + public = true, + actions = function() getshape("parshape") end, +} +implement { + name = "getclubpenalties", + public = true, + actions = function() getshape("clubpenalties") end, +} +implement { + name = "getinterlinepenalties", + public = true, + actions = function() getshape("interlinepenalties") end, + } +implement { + name = "getdisplaywidowpenalties", + public = true, + actions = function() getshape("displaywidowpenalties") end, +} +implement { + name = "getwidowpenalties", + public = true, + actions = function() getshape("widowpenalties") end, +} diff --git a/tex/context/base/mkiv/toks-ini.lua b/tex/context/base/mkiv/toks-ini.lua index eef26574e..594fb4743 100644 --- a/tex/context/base/mkiv/toks-ini.lua +++ b/tex/context/base/mkiv/toks-ini.lua @@ -39,6 +39,7 @@ local scan_code = token.scan_code local scan_token_code = token.scan_token_code local scan_dimen = token.scan_dimen local scan_glue = token.scan_glue +local scan_gluespec = token.scan_skip local scan_keyword = token.scan_keyword local scan_keyword_cs = token.scan_keyword_cs or scan_keyword local scan_token = token.scan_token @@ -164,7 +165,7 @@ tokens.scanners = { -- these expand dimen = scan_dimen, dimension = scan_dimen, glue = scan_glue, - skip = scan_glue, + gluespec = scan_gluespec, integer = scan_int, real = scan_real, float = scan_float, diff --git a/tex/context/base/mkiv/toks-scn.lua b/tex/context/base/mkiv/toks-scn.lua index 2d20d5a8b..fcbdec5a0 100644 --- a/tex/context/base/mkiv/toks-scn.lua +++ b/tex/context/base/mkiv/toks-scn.lua @@ -262,6 +262,7 @@ local f_any_all_c= formatters[" local key = scanword() if key then data[key] = local f_table = formatters["%\nt\nreturn function()\n local data = { }\n%s\n return %s\nend\n"] local f_sequence = formatters["%\nt\n%\nt\n%\nt\nreturn function()\n return %s\nend\n"] +local f_singular = formatters["%\nt\n%\nt\n\nreturn function(%s)\n return %s\nend\n"] local f_simple = formatters["%\nt\nreturn function()\n return %s\nend\n"] local f_string = formatters["%q"] local f_action_f = formatters["action%s(%s)"] @@ -331,6 +332,7 @@ function tokens.compile(specification) a = { a } end local code + local args local function compile(t,nested) local done = s_done local r = { } @@ -437,6 +439,23 @@ function tokens.compile(specification) else return scanners[ti] end + elseif #t == 0 then + if specification.valuetype then + code = "b" + args = "_,b" + else + code = "" + args = "" + end + if a then + tokens._action = a + for i=1,#a do + code = f_action_f(i,code) + n = n + 1 + f[n] = f_action_s(i,i) + end + end + code = f_singular(c,f,args,code) else local r = { } local p = { } diff --git a/tex/context/base/mkiv/typo-del.mkiv b/tex/context/base/mkiv/typo-del.mkiv index 9320c37ee..afa7e0ffe 100644 --- a/tex/context/base/mkiv/typo-del.mkiv +++ b/tex/context/base/mkiv/typo-del.mkiv @@ -524,6 +524,7 @@ \begingroup \usedelimitedtextstyleandcolor\c!style\c!color % + \begingroup \edef\p_delimited_left {\delimitedtextparameter{\c!left}}% \edef\p_delimited_right {\delimitedtextparameter{\c!right}}% \edef\p_delimited_nextleft {\delimitedtextparameter{\c!nextleft}}% @@ -539,7 +540,10 @@ \def\typo_delimited_stop_par {\typo_delimited_stop_content \rightdelimitedtextmark - \carryoverpar\endgroup % new per 2013-01-21 ... please left floats + \rightdelimitedtextmark + \carryoverpar\endgroup + \endgraf + \endgroup \pop_macro_checkindentation \typo_delimited_stop_par_indeed \delimitedtextparameter\c!after diff --git a/tex/context/base/mkiv/util-tab.lua b/tex/context/base/mkiv/util-tab.lua index 4dafb2acd..9f7112eb9 100644 --- a/tex/context/base/mkiv/util-tab.lua +++ b/tex/context/base/mkiv/util-tab.lua @@ -961,3 +961,12 @@ function table.ordered(t) return function() end end end + +-- function table.randomremove(t,n) +-- if not n then +-- n = #t +-- end +-- if n > 0 then +-- return remove(t,random(1,n)) +-- end +-- end diff --git a/tex/context/fonts/mkiv/type-imp-plex.mkiv b/tex/context/fonts/mkiv/type-imp-plex.mkiv index 4087cd64d..1e94306bc 100644 --- a/tex/context/fonts/mkiv/type-imp-plex.mkiv +++ b/tex/context/fonts/mkiv/type-imp-plex.mkiv @@ -48,7 +48,7 @@ \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:plex\typescriptone}] \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-lightitalic][\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % extralight |