diff options
Diffstat (limited to 'tex')
60 files changed, 5605 insertions, 294 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index 5536dd894..876eacdfc 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{2021.11.30 19:43} +\newcontextversion{2021.12.03 15:17} %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 9f51621bf..48af7f8e3 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{2021.11.30 19:43} +\edef\contextversion{2021.12.03 15:17} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-pe.mkii b/tex/context/base/mkii/mult-pe.mkii index 410fa7590..290da95f2 100644 --- a/tex/context/base/mkii/mult-pe.mkii +++ b/tex/context/base/mkii/mult-pe.mkii @@ -1282,6 +1282,7 @@ \setinterfaceconstant{tab}{تب} \setinterfaceconstant{text}{متن} \setinterfaceconstant{textalign}{textalign} +\setinterfaceconstant{textalternative}{textalternative} \setinterfaceconstant{textcolor}{رنگمتن} \setinterfaceconstant{textcommand}{فرمانمتن} \setinterfaceconstant{textdistance}{فاصلهمتن} diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 529d7448d..92172d354 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{2021.11.30 19:43} +\newcontextversion{2021.12.03 15:17} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 956425aa6..fa300cafd 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -49,7 +49,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2021.11.30 19:43} +\edef\contextversion{2021.12.03 15:17} %D Kind of special: diff --git a/tex/context/base/mkiv/font-imp-properties.lua b/tex/context/base/mkiv/font-imp-properties.lua index 21b55aeb2..5405737a5 100644 --- a/tex/context/base/mkiv/font-imp-properties.lua +++ b/tex/context/base/mkiv/font-imp-properties.lua @@ -72,10 +72,10 @@ do extra = amount end end - parameters.space = amount * emwidth - parameters.space_stretch = stretch * emwidth - parameters.space_shrink = shrink * emwidth - parameters.extra_space = extra * emwidth + parameters.space = amount * emwidth + parameters.spacestretch = stretch * emwidth + parameters.spaceshrink = shrink * emwidth + parameters.extraspace = extra * emwidth end end diff --git a/tex/context/base/mkiv/lpdf-ini.lua b/tex/context/base/mkiv/lpdf-ini.lua index 1098ef8fa..07e9c8df8 100644 --- a/tex/context/base/mkiv/lpdf-ini.lua +++ b/tex/context/base/mkiv/lpdf-ini.lua @@ -1410,7 +1410,8 @@ do return timestamp end - lpdf.settime(tonumber(resolvers.variable("start_time")) or tonumber(resolvers.variable("SOURCE_DATE_EPOCH"))) -- bah + -- lpdf.settime(tonumber(resolvers.variable("starttime")) or tonumber(resolvers.variable("SOURCE_DATE_EPOCH"))) -- bah + lpdf.settime(tonumber(resolvers.variable("starttime"))) function lpdf.pdftimestamp(str) local t = type(str) diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 2c0d9d41b..87c52de04 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -301,6 +301,8 @@ return { "crampedscriptstyle", "crampedtextstyle", "csstring", + "currentloopiterator", + "currentloopnesting", "currentmarks", "defcsname", "dimensiondef", @@ -320,6 +322,7 @@ return { "expandafterspaces", "expandcstoken", "expanded", + "expandedloop", "expandtoken", "explicitdiscretionary", "explicithyphenpenalty", @@ -434,6 +437,7 @@ return { "localbrokenpenalty", "localcontrol", "localcontrolled", + "localcontrolledloop", "localinterlinepenalty", "localleftbox", "localleftboxbox", @@ -507,6 +511,7 @@ return { "protrudechars", "protrusionboundary", "pxdimen", + "quitloop", "quitvmode", "retokenized", "rightmarginkern", @@ -539,6 +544,7 @@ return { "tracingmarks", "tracingmath", "undent", + "unexpandedloop", "unletfrozen", "unletprotected", "untraced", diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 2cd4adcf2..41707d50a 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 9c5a72289..40471b66f 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkxl/blob-ini.mkxl b/tex/context/base/mkxl/blob-ini.mkxl index 1dcd55972..2e27ab20e 100644 --- a/tex/context/base/mkxl/blob-ini.mkxl +++ b/tex/context/base/mkxl/blob-ini.mkxl @@ -18,7 +18,7 @@ %D down the road (close to version 1.00 of \LUATEX). Typesetting in %D pure \LUA\ sometimes makes sense. -\registerctxluafile{node-typ}{} % experimental +\registerctxluafile{node-typ}{autosuffix} % experimental \registerctxluafile{blob-ini}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl index 3bfffe608..95430abf6 100644 --- a/tex/context/base/mkxl/cont-new.mkxl +++ b/tex/context/base/mkxl/cont-new.mkxl @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2021.11.30 19:43} +\newcontextversion{2021.12.03 15:17} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl index 854c65e98..914f4bfd9 100644 --- a/tex/context/base/mkxl/context.mkxl +++ b/tex/context/base/mkxl/context.mkxl @@ -29,7 +29,7 @@ %D {YYYY.MM.DD HH:MM} format. \immutable\edef\contextformat {\jobname} -\immutable\edef\contextversion{2021.11.30 19:43} +\immutable\edef\contextversion{2021.12.03 15:17} %overloadmode 1 % check frozen / warning %overloadmode 2 % check frozen / error diff --git a/tex/context/base/mkxl/font-chk.lmt b/tex/context/base/mkxl/font-chk.lmt index 967431423..008b9bb41 100644 --- a/tex/context/base/mkxl/font-chk.lmt +++ b/tex/context/base/mkxl/font-chk.lmt @@ -379,13 +379,13 @@ local function expandglyph(characters,index,done) if n then d.next = expandglyph(characters,n,done) end - local h = d.horiz_variants + local h = d.hvariants if h then for i=1,#h do h[i].glyph = expandglyph(characters,h[i].glyph,done) end end - local v = d.vert_variants + local v = d.vvariants if v then for i=1,#v do v[i].glyph = expandglyph(characters,v[i].glyph,done) diff --git a/tex/context/base/mkxl/font-con.lmt b/tex/context/base/mkxl/font-con.lmt index b452f5a12..3310242a8 100644 --- a/tex/context/base/mkxl/font-con.lmt +++ b/tex/context/base/mkxl/font-con.lmt @@ -161,17 +161,17 @@ function constructors.trytosharefont(target,tfmdata) end local synonyms = { - exheight = "x_height", - xheight = "x_height", - ex = "x_height", + exheight = "xheight", + xheight = "xheight", + ex = "xheight", emwidth = "quad", em = "quad", - spacestretch = "space_stretch", - stretch = "space_stretch", - spaceshrink = "space_shrink", - shrink = "space_shrink", - extraspace = "extra_space", - xspace = "extra_space", + spacestretch = "spacestretch", + stretch = "spacestretch", + spaceshrink = "spaceshrink", + shrink = "spaceshrink", + extraspace = "extraspace", + xspace = "extraspace", slantperpoint = "slant", } @@ -188,9 +188,9 @@ function constructors.enhanceparameters(parameters) if k == "spacing" then return { width = t.space, - stretch = t.space_stretch, - shrink = t.space_shrink, - extra = t.extra_space, + stretch = t.spacestretch, + shrink = t.spaceshrink, + extra = t.extraspace, } end return mt and mt[k] or nil @@ -205,9 +205,9 @@ function constructors.enhanceparameters(parameters) elseif k == "spacing" then if type(v) == "table" then rawset(t,"space",v.width or 0) - rawset(t,"space_stretch",v.stretch or 0) - rawset(t,"space_shrink",v.shrink or 0) - rawset(t,"extra_space",v.extra or 0) + rawset(t,"spacestretch",v.stretch or 0) + rawset(t,"spaceshrink",v.shrink or 0) + rawset(t,"extraspace",v.extra or 0) end else rawset(t,k,v) @@ -437,21 +437,21 @@ function constructors.scale(tfmdata,specification) -- target.postprocessors = tfmdata.postprocessors -- - local targetslant = (parameters.slant or parameters[1] or 0) * factors.pt -- per point - local targetspace = (parameters.space or parameters[2] or 0) * hdelta - local targetspace_stretch = (parameters.space_stretch or parameters[3] or 0) * hdelta - local targetspace_shrink = (parameters.space_shrink or parameters[4] or 0) * hdelta - local targetx_height = (parameters.x_height or parameters[5] or 0) * vdelta - local targetquad = (parameters.quad or parameters[6] or 0) * hdelta - local targetextra_space = (parameters.extra_space or parameters[7] or 0) * hdelta - -- - targetparameters.slant = targetslant -- slantperpoint - targetparameters.space = targetspace - targetparameters.space_stretch = targetspace_stretch - targetparameters.space_shrink = targetspace_shrink - targetparameters.x_height = targetx_height - targetparameters.quad = targetquad - targetparameters.extra_space = targetextra_space + local targetslant = (parameters.slant or parameters[1] or 0) * factors.pt -- per point + local targetspace = (parameters.space or parameters[2] or 0) * hdelta + local targetspacestretch = (parameters.spacestretch or parameters[3] or 0) * hdelta + local targetspaceshrink = (parameters.spaceshrink or parameters[4] or 0) * hdelta + local targetxheight = (parameters.xheight or parameters[5] or 0) * vdelta + local targetquad = (parameters.quad or parameters[6] or 0) * hdelta + local targetextraspace = (parameters.extraspace or parameters[7] or 0) * hdelta + -- + targetparameters.slant = targetslant -- slantperpoint + targetparameters.space = targetspace + targetparameters.spacestretch = targetspacestretch + targetparameters.spaceshrink = targetspaceshrink + targetparameters.xheight = targetxheight + targetparameters.quad = targetquad + targetparameters.extraspace = targetextraspace -- local hshift = parameters.hshift if hshift then @@ -653,17 +653,17 @@ function constructors.scale(tfmdata,specification) end if hasquality then -- we could move these calculations elsewhere (saves calculations) - local ve = character.expansion_factor + local ve = character.expansion if ve then - chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere + chr.expansion = ve*1000 -- expansionfactor, hm, can happen elsewhere end - local vl = character.left_protruding + local vl = character.leftprotrusion if vl then - chr.left_protruding = width*vl + chr.leftprotrusion = width*vl end - local vr = character.right_protruding + local vr = character.rightprotrusion if vr then - chr.right_protruding = width*vr + chr.rightprotrusion = width*vr end end -- @@ -674,7 +674,7 @@ function constructors.scale(tfmdata,specification) if vn then chr.next = vn else - local vv = character.vert_variants + local vv = character.vvariants if vv then local t = { } for i=1,#vv do @@ -690,9 +690,9 @@ function constructors.scale(tfmdata,specification) ["glyph"] = vvi["glyph"], } end - chr.vert_variants = t + chr.vvariants = t else - local hv = character.horiz_variants + local hv = character.hvariants if hv then local t = { } for i=1,#hv do @@ -708,18 +708,18 @@ function constructors.scale(tfmdata,specification) ["glyph"] = hvi["glyph"], } end - chr.horiz_variants = t + chr.hvariants = t end end -- todo also check mathitalics (or that one can go away) end - local vi = character.vert_italic + local vi = character.vitalic if vi and vi ~= 0 then - chr.vert_italic = vi*hdelta + chr.vitalic = vi*hdelta end local va = character.accent if va then - chr.top_accent = vdelta*va + chr.topaccent = vdelta*va end if stackmath then local mk = character.mathkerns @@ -729,10 +729,10 @@ function constructors.scale(tfmdata,specification) local br = mk.bottomright local bl = mk.bottomleft chr.mathkern = { -- singular -> should be patched in luatex ! - top_right = tr and mathkerns(tr,vdelta) or nil, - top_left = tl and mathkerns(tl,vdelta) or nil, - bottom_right = br and mathkerns(br,vdelta) or nil, - bottom_left = bl and mathkerns(bl,vdelta) or nil, + topright = tr and mathkerns(tr,vdelta) or nil, + topleft = tl and mathkerns(tl,vdelta) or nil, + bottomright = br and mathkerns(br,vdelta) or nil, + bottomleft = bl and mathkerns(bl,vdelta) or nil, } end end diff --git a/tex/context/base/mkxl/font-ctx.lmt b/tex/context/base/mkxl/font-ctx.lmt index ed8c22f58..05cad84f0 100644 --- a/tex/context/base/mkxl/font-ctx.lmt +++ b/tex/context/base/mkxl/font-ctx.lmt @@ -303,14 +303,14 @@ function definers.resetnullfont() -- resetting is needed because tikz misuses nullfont local parameters = fonts.nulldata.parameters -- - parameters.slant = 0 -- 1 - parameters.space = 0 -- 2 - parameters.space_stretch = 0 -- 3 - parameters.space_shrink = 0 -- 4 - parameters.x_height = 0 -- 5 - parameters.quad = 0 -- 6 - parameters.extra_space = 0 -- 7 - parameters.designsize = 655360 + parameters.slant = 0 -- 1 + parameters.space = 0 -- 2 + parameters.spacestretch = 0 -- 3 + parameters.spaceshrink = 0 -- 4 + parameters.xheight = 0 -- 5 + parameters.quad = 0 -- 6 + parameters.extraspace = 0 -- 7 + parameters.designsize = 655360 -- constructors.enhanceparameters(parameters) -- official copies for us -- diff --git a/tex/context/base/mkxl/font-hsh.lmt b/tex/context/base/mkxl/font-hsh.lmt new file mode 100644 index 000000000..594f47332 --- /dev/null +++ b/tex/context/base/mkxl/font-hsh.lmt @@ -0,0 +1,397 @@ +if not modules then modules = { } end modules ['font-hsh'] = { + 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" +} + +local rawget = rawget + +local setmetatableindex = table.setmetatableindex +local currentfont = font and font.current -- used in the web service +local allocate = utilities.storage.allocate + +local fonts = fonts +local hashes = fonts.hashes or allocate() +fonts.hashes = hashes + +-- todo: autoallocate ... just create on the fly .. use constructors.keys (problem: plurals) + +local identifiers = hashes.identifiers or allocate() +local characters = hashes.characters or allocate() -- chardata +local descriptions = hashes.descriptions or allocate() +local parameters = hashes.parameters or allocate() +local mathparameters = hashes.mathparameters or allocate() +local properties = hashes.properties or allocate() +local resources = hashes.resources or allocate() +local spacings = hashes.spacings or allocate() +local spaces = hashes.spaces or allocate() +local quads = hashes.quads or allocate() -- maybe also spacedata +local xheights = hashes.xheights or allocate() +local csnames = hashes.csnames or allocate() -- namedata +local features = hashes.features or allocate() +local marks = hashes.marks or allocate() +local classes = hashes.classes or allocate() +local italics = hashes.italics or allocate() +local lastmathids = hashes.lastmathids or allocate() +local dynamics = hashes.dynamics or allocate() +local unicodes = hashes.unicodes or allocate() +local unislots = hashes.unislots or allocate() +local originals = hashes.originals or allocate() +local modes = hashes.modes or allocate() +local variants = hashes.variants or allocate() + +hashes.characters = characters +hashes.descriptions = descriptions +hashes.parameters = parameters +hashes.mathparameters = mathparameters +hashes.properties = properties +hashes.resources = resources +hashes.spacings = spacings +hashes.spaces = spaces +hashes.quads = quads hashes.emwidths = quads +hashes.xheights = xheights hashes.exheights = xheights +hashes.csnames = csnames +hashes.features = features +hashes.marks = marks +hashes.classes = classes +hashes.italics = italics +hashes.lastmathids = lastmathids +hashes.dynamics = dynamics +hashes.unicodes = unicodes +hashes.unislots = unislots +hashes.originals = originals +hashes.modes = modes +hashes.variants = variants + +local nodepool = nodes and nodes.pool +local dummyglyph = nodepool and nodepool.register(nodepool.glyph()) + +local nulldata = allocate { + name = "nullfont", + characters = { }, + descriptions = { }, + properties = { + designsize = 786432, -- really ? maybe move to 655360 instead + }, + parameters = { -- lmromanregular @ 12pt + slantperpoint = 0, + spacing = { + width = 256377, + stretch = 128188, + shrink = 85459, + extra = 85459, + }, + quad = 786432, + size = 786432, + slant = 0, -- 1 + space = 256377, -- 2 + spacestretch = 128188, -- 3 + spaceshrink = 85459, -- 4 + xheight = 338952, -- 5 + quad = 786432, -- 6 + extraspace = 85459, -- 7 + }, +} + +fonts.nulldata = nulldata + +fonts.constructors.enhanceparameters(nulldata.parameters) -- official copies for us + +setmetatableindex(identifiers, function(t,k) + return k == true and identifiers[currentfont()] or nulldata +end) + +if font then + + -- to be used + + local define = font.define + local setfont = font.setfont + local frozen = font.frozen + + function fonts.reserveid(fontdata) + return define(fontdata or nulldata) + end + + function fonts.enhanceid(id,fontdata) + if not frozen(id) then + setfont(id,fontdata) + end + end + +end + +setmetatableindex(characters, function(t,k) + if k == true then + return characters[currentfont()] + else + local characters = identifiers[k].characters + t[k] = characters + return characters + end +end) + +setmetatableindex(descriptions, function(t,k) + if k == true then + return descriptions[currentfont()] + else + local descriptions = identifiers[k].descriptions + t[k] = descriptions + return descriptions + end +end) + +setmetatableindex(parameters, function(t,k) + if k == true then + return parameters[currentfont()] + else + local parameters = identifiers[k].parameters + t[k] = parameters + return parameters + end +end) + +setmetatableindex(mathparameters, function(t,k) + if k == true then + return mathparameters[currentfont()] + else + local mathparameters = identifiers[k].mathparameters + t[k] = mathparameters + return mathparameters + end +end) + +setmetatableindex(properties, function(t,k) + if k == true then + return properties[currentfont()] + else + local properties = identifiers[k].properties + t[k] = properties + return properties + end +end) + +setmetatableindex(resources, function(t,k) + if k == true then + return resources[currentfont()] + else + local shared = identifiers[k].shared + local rawdata = shared and shared.rawdata + local resources = rawdata and rawdata.resources + t[k] = resources or false -- better than resolving each time + return resources + end +end) + +setmetatableindex(features, function(t,k) + if k == true then + return features[currentfont()] + else + local shared = identifiers[k].shared + local features = shared and shared.features or { } + t[k] = features + return features + end +end) + +local nospacing = { + width = 0, + stretch = 0, + shrink = 0, + extra = 0, +} + +setmetatableindex(spacings, function(t,k) + if k == true then + return spacings[currentfont()] + else + local parameters = parameters[k] + local spacing = parameters and parameters.spacing or nospacing + t[k] = spacing + return spacing + end +end) + +setmetatableindex(spaces, function(t,k) + if k == true then + return spaces[currentfont()] + else + local space = spacings[k].width + t[k] = space + return space + end +end) + +setmetatableindex(marks, function(t,k) + if k == true then + return marks[currentfont()] + else + local resources = identifiers[k].resources or { } + local marks = resources.marks or { } + t[k] = marks + return marks + end +end) + +setmetatableindex(classes, function(t,k) + if k == true then + return classes[currentfont()] + else + local resources = identifiers[k].resources or { } + local classes = resources.classes or { } + t[k] = classes + return classes + end +end) + +setmetatableindex(quads, function(t,k) + if k == true then + return quads[currentfont()] + else + local parameters = rawget(parameters,k) + local quad + if parameters then + quad = parameters.quad + elseif dummyglyph then + dummyglyph.font = k + dummyglyph.char = 0x2014 -- emdash + quad = dummyglyph.width -- dirty trick + end + if not quad or quad == 0 then + quad = 655360 -- lm 10pt + end + t[k] = quad + return quad + end +end) + +setmetatableindex(xheights, function(t,k) + if k == true then + return xheights[currentfont()] + else + local parameters = rawget(parameters,k) + local xheight + if parameters then + xheight = parameters.xheight + elseif dummyglyph then + dummyglyph.font = k + dummyglyph.char = 0x78 -- x + xheight = dummyglyph.height -- dirty trick + end + if not xheight or xheight == 0 then + xheight = 282460 -- lm 10pt + end + t[k] = xheight + return xheight + end +end) + +setmetatableindex(italics, function(t,k) -- is test ! + if k == true then + return italics[currentfont()] + else + local properties = identifiers[k].properties + local hasitalics = properties and properties.hasitalics + if hasitalics then + hasitalics = characters[k] -- convenient return + else + hasitalics = false + end + t[k] = hasitalics + return hasitalics + end +end) + +setmetatableindex(dynamics, function(t,k) + if k == true then + return dynamics[currentfont()] + else + local shared = identifiers[k].shared + local dynamics = shared and shared.dynamics or false + t[k] = dynamics + return dynamics + end +end) + +setmetatableindex(unicodes, function(t,k) -- always a unicode + if k == true then + return unicodes[currentfont()] + else + local resources = resources[k] + local unicodes = resources and resources.unicodes or { } + t[k] = unicodes + return unicodes + end +end) + +setmetatableindex(originals, function(t,k) -- always a unicode + if k == true then + return originals[currentfont()] + else + local resolved = { } + setmetatableindex(resolved,function(t,name) + local u = unicodes[k][name] + local d = u and descriptions[k][u] + local v = d and d.unicode or u or 0 -- so we return notdef (at least for the moment) + t[name] = u + return v + end) + t[k] = resolved + return resolved + end +end) + +setmetatableindex(unislots, function(t,k) + if k == true then + return unislots[currentfont()] + else + local characters = identifiers[k].characters + local resolved = setmetatableindex(function(t,k) + local c = characters[k] + local v = c and c.unicode or 0xFFFD + t[k] = v + return v -- can be a table ! + end) + t[k] = resolved + return resolved + end +end) + +setmetatableindex(modes, function(t,k) + if k == true then + return modes[currentfont()] + else + local mode = properties[k].mode or "base" + t[k] = mode + return mode + end +end) + +setmetatableindex(variants, function(t,k) + if k == true then + return variants[currentfont()] + else + local resources = resources[k] + if resources then + local variants = resources.variants + if variants and next(variants) then + t[k] = variants + return variants + end + end + t[k] = false + return false + end +end) + +if font then + + function font.getfont(id) + return identifiers[id] + end + +end + +-- font.setfont = currentfont -- bah, no native 'setfont' as name diff --git a/tex/context/base/mkxl/font-imp-quality.lmt b/tex/context/base/mkxl/font-imp-quality.lmt new file mode 100644 index 000000000..93ec1b653 --- /dev/null +++ b/tex/context/base/mkxl/font-imp-quality.lmt @@ -0,0 +1,583 @@ +if not modules then modules = { } end modules ['font-imp-quality'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-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 end + +local next, type, tonumber = next, type, tonumber + +local fonts = fonts +local utilities = utilities + +local handlers = fonts.handlers +local otf = handlers.otf +local afm = handlers.afm +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register + +local allocate = utilities.storage.allocate +local getparameters = utilities.parsers.getparameters + +local implement = interfaces and interfaces.implement + +local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) +local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) + +local report_expansions = logs.reporter("fonts","expansions") +local report_protrusions = logs.reporter("fonts","protrusions") + +-- -- -- -- -- -- +-- shared +-- -- -- -- -- -- + +local function get_class_and_vector(tfmdata,value,where) -- "expansions" + local g_where = tfmdata.goodies and tfmdata.goodies[where] + local f_where = fonts[where] + local g_classes = g_where and g_where.classes + local f_classes = f_where and f_where.classes + local class = (g_classes and g_classes[value]) or (f_classes and f_classes[value]) + if class then + local class_vector = class.vector + local g_vectors = g_where and g_where.vectors + local f_vectors = f_where and f_where.vectors + local vector = (g_vectors and g_vectors[class_vector]) or (f_vectors and f_vectors[class_vector]) + return class, vector + end +end + +-- -- -- -- -- -- +-- expansion (hz) +-- -- -- -- -- -- + +local expansions = fonts.expansions or allocate() + +fonts.expansions = expansions + +local classes = expansions.classes or allocate() +local vectors = expansions.vectors or allocate() + +expansions.classes = classes +expansions.vectors = vectors + +classes.preset = { + stretch = 2, + shrink = 2, + step = .5, + factor = 1, +} + +classes['quality'] = { + stretch = 2, + shrink = 2, + step = .5, + vector = 'default', + factor = 1, +} + +vectors['default'] = { + [0x0041] = 0.5, -- A + [0x0042] = 0.7, -- B + [0x0043] = 0.7, -- C + [0x0044] = 0.5, -- D + [0x0045] = 0.7, -- E + [0x0046] = 0.7, -- F + [0x0047] = 0.5, -- G + [0x0048] = 0.7, -- H + [0x004B] = 0.7, -- K + [0x004D] = 0.7, -- M + [0x004E] = 0.7, -- N + [0x004F] = 0.5, -- O + [0x0050] = 0.7, -- P + [0x0051] = 0.5, -- Q + [0x0052] = 0.7, -- R + [0x0053] = 0.7, -- S + [0x0055] = 0.7, -- U + [0x0057] = 0.7, -- W + [0x005A] = 0.7, -- Z + [0x0061] = 0.7, -- a + [0x0062] = 0.7, -- b + [0x0063] = 0.7, -- c + [0x0064] = 0.7, -- d + [0x0065] = 0.7, -- e + [0x0067] = 0.7, -- g + [0x0068] = 0.7, -- h + [0x006B] = 0.7, -- k + [0x006D] = 0.7, -- m + [0x006E] = 0.7, -- n + [0x006F] = 0.7, -- o + [0x0070] = 0.7, -- p + [0x0071] = 0.7, -- q + [0x0073] = 0.7, -- s + [0x0075] = 0.7, -- u + [0x0077] = 0.7, -- w + [0x007A] = 0.7, -- z + [0x0032] = 0.7, -- 2 + [0x0033] = 0.7, -- 3 + [0x0036] = 0.7, -- 6 + [0x0038] = 0.7, -- 8 + [0x0039] = 0.7, -- 9 +} + +vectors['quality'] = vectors['default'] -- metatable ? + +local function initialize(tfmdata,value) + if value then + local class, vector = get_class_and_vector(tfmdata,value,"expansions") + if class then + if vector then + local stretch = class.stretch or 0 + local shrink = class.shrink or 0 + local step = class.step or 0 + local factor = class.factor or 1 + if trace_expansion then + report_expansions("setting class %a, vector %a, factor %a, stretch %a, shrink %a, step %a", + value,class.vector,factor,stretch,shrink,step) + end + tfmdata.parameters.expansion = { + stretch = 10 * stretch, + shrink = 10 * shrink, + step = 10 * step, + factor = factor, + } + local data = characters and characters.data + for i, chr in next, tfmdata.characters do + local v = vector[i] + if data and not v then -- we could move the data test outside (needed for plain) + local d = data[i] + if d then + local s = d.shcode + if not s then + -- sorry + elseif type(s) == "table" then + v = ((vector[s[1]] or 0) + (vector[s[#s]] or 0)) / 2 + else + v = vector[s] or 0 + end + end + end + if v and v ~= 0 then + chr.expansion = v*factor + else -- can be option + chr.expansion = factor + end + end + elseif trace_expansion then + report_expansions("unknown vector %a in class %a",class.vector,value) + end + elseif trace_expansion then + report_expansions("unknown class %a",value) + end + end +end + +local specification = { + name = "expansion", + description = "apply hz optimization", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end) + +implement { + name = "setupfontexpansion", + arguments = "2 strings", + actions = function(class,settings) getparameters(classes,class,'preset',settings) end +} + +-- -- -- -- -- -- +-- protrusion +-- -- -- -- -- -- + +fonts.protrusions = allocate() +local protrusions = fonts.protrusions + +protrusions.classes = allocate() +protrusions.vectors = allocate() + +local classes = protrusions.classes +local vectors = protrusions.vectors + +-- the values need to be revisioned + +classes.preset = { + factor = 1, + left = 1, + right = 1, +} + +classes['pure'] = { vector = 'pure', factor = 1 } +classes['punctuation'] = { vector = 'punctuation', factor = 1 } +classes['alpha'] = { vector = 'alpha', factor = 1 } +classes['quality'] = { vector = 'quality', factor = 1 } + +vectors['pure'] = { + + [0x002C] = { 0, 1 }, -- comma + [0x002E] = { 0, 1 }, -- period + [0x003A] = { 0, 1 }, -- colon + [0x003B] = { 0, 1 }, -- semicolon + [0x002D] = { 0, 1 }, -- hyphen + [0x00AD] = { 0, 1 }, -- also hyphen + [0x2013] = { 0, 0.50 }, -- endash + [0x2014] = { 0, 0.33 }, -- emdash + [0x3001] = { 0, 1 }, -- ideographic comma 、 + [0x3002] = { 0, 1 }, -- ideographic full stop 。 + [0x060C] = { 0, 1 }, -- arabic comma ، + [0x061B] = { 0, 1 }, -- arabic semicolon ؛ + [0x06D4] = { 0, 1 }, -- arabic full stop ۔ + +} + +vectors['punctuation'] = { + + [0x003F] = { 0, 0.20 }, -- ? + [0x00BF] = { 0.20, 0 }, -- ¿ + [0x0021] = { 0, 0.20 }, -- ! + [0x00A1] = { 0.20, 0, }, -- ¡ + [0x0028] = { 0.05, 0 }, -- ( + [0x0029] = { 0, 0.05 }, -- ) + [0x005B] = { 0.05, 0 }, -- [ + [0x005D] = { 0, 0.05 }, -- ] + [0x002C] = { 0, 0.70 }, -- comma + [0x002E] = { 0, 0.70 }, -- period + [0x003A] = { 0, 0.50 }, -- colon + [0x003B] = { 0, 0.50 }, -- semicolon + [0x002D] = { 0, 0.70 }, -- hyphen + [0x00AD] = { 0, 0.70 }, -- also hyphen + [0x2013] = { 0, 0.30 }, -- endash + [0x2014] = { 0, 0.20 }, -- emdash + [0x060C] = { 0, 0.70 }, -- arabic comma + [0x061B] = { 0, 0.50 }, -- arabic semicolon + [0x06D4] = { 0, 0.70 }, -- arabic full stop + [0x061F] = { 0, 0.20 }, -- ؟ + + -- todo: left and right quotes: .5 double, .7 single + + [0x2039] = { 0.70, 0.70 }, -- left single guillemet ‹ + [0x203A] = { 0.70, 0.70 }, -- right single guillemet › + [0x00AB] = { 0.50, 0.50 }, -- left guillemet « + [0x00BB] = { 0.50, 0.50 }, -- right guillemet » + + [0x2018] = { 0.70, 0.70 }, -- left single quotation mark ‘ + [0x2019] = { 0, 0.70 }, -- right single quotation mark ’ + [0x201A] = { 0.70, 0 }, -- single low-9 quotation mark , + [0x201B] = { 0.70, 0 }, -- single high-reversed-9 quotation mark ‛ + [0x201C] = { 0.50, 0.50 }, -- left double quotation mark “ + [0x201D] = { 0, 0.50 }, -- right double quotation mark ” + [0x201E] = { 0.50, 0 }, -- double low-9 quotation mark „ + [0x201F] = { 0.50, 0 }, -- double high-reversed-9 quotation mark ‟ + +} + +vectors['alpha'] = { + + [0x0041] = { .05, .05 }, -- A + [0x0046] = { 0, .05 }, -- F + [0x004A] = { .05, 0 }, -- J + [0x004B] = { 0, .05 }, -- K + [0x004C] = { 0, .05 }, -- L + [0x0054] = { .05, .05 }, -- T + [0x0056] = { .05, .05 }, -- V + [0x0057] = { .05, .05 }, -- W + [0x0058] = { .05, .05 }, -- X + [0x0059] = { .05, .05 }, -- Y + + [0x006B] = { 0, .05 }, -- k + [0x0072] = { 0, .05 }, -- r + [0x0074] = { 0, .05 }, -- t + [0x0076] = { .05, .05 }, -- v + [0x0077] = { .05, .05 }, -- w + [0x0078] = { .05, .05 }, -- x + [0x0079] = { .05, .05 }, -- y + +} + +vectors['quality'] = table.merged( + vectors['punctuation'], + vectors['alpha'] +) + +-- As this is experimental code, users should not depend on it. The implications are still +-- discussed on the ConTeXt Dev List and we're not sure yet what exactly the spec is (the +-- next code is tested with a gyre font patched by / fea file made by Khaled Hosny). The +-- double trick should not be needed it proper hanging punctuation is used in which case +-- values < 1 can be used. +-- +-- preferred (in context, usine vectors): +-- +-- \definefontfeature[whatever][default][mode=node,protrusion=quality] +-- +-- using lfbd and rtbd, with possibibility to enable only one side : +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn] +-- +-- idem, using multiplier +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn] +-- +-- idem, using named feature file (less frozen): +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea] + +classes['double'] = { -- for testing opbd + factor = 2, + left = 1, + right = 1, +} + +local function map_opbd_onto_protrusion(tfmdata,value,opbd) + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local properties = tfmdata.properties + local parameters = tfmdata.parameters + local resources = tfmdata.resources + local rawdata = tfmdata.shared.rawdata + local lookuphash = rawdata.lookuphash + local lookuptags = resources.lookuptags + local script = properties.script + local language = properties.language + local units = parameters.units + local done, factor, left, right = false, 1, 1, 1 + local class = classes[value] + if class then + factor = class.factor or 1 + left = class.left or 1 + right = class.right or 1 + else + factor = tonumber(value) or 1 + end + local lfactor = left * factor + local rfactor = right * factor + if trace_protrusion then + report_protrusions("left factor %0.3F, right factor %0.3F",lfactor,rfactor) + end + tfmdata.parameters.protrusion = { + factor = factor, + left = left, + right = right, + } + if opbd ~= "right" then + local validlookups, lookuplist = otf.collectlookups(rawdata,"lfbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local steps = lookup.steps + if steps then + if trace_protrusion then + report_protrusions("setting left using lfbd") + end + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + if coverage then + for k, v in next, coverage do + if v == true then + -- zero + else + local w = descriptions[k].width + local d = - v[1] + if w == 0 or d == 0 then + -- ignored + else + local p = lfactor * d/units + characters[k].leftprotrusion = p + if trace_protrusion then + report_protrusions("lfbd -> %0.3F %C",p,k) + end + end + end + end + end + end + done = true + end + end + end + end + if opbd ~= "left" then + local validlookups, lookuplist = otf.collectlookups(rawdata,"rtbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local steps = lookup.steps + if steps then + if trace_protrusion then + report_protrusions("setting right using rtbd") + end + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + if coverage then + for k, v in next, coverage do + if v == true then + -- zero + else + local w = descriptions[k].width + local d = - v[3] + if w == 0 or d == 0 then + -- ignored + else + local p = rfactor * d/units + characters[k].rightprotrusion = p + if trace_protrusion then + report_protrusions("rtbd -> %0.3F %C",p,k) + end + end + end + end + end + end + end + done = true + end + end + end +end + +-- The opbd test is just there because it was discussed on the context development list. However, +-- the mentioned fxlbi.otf font only has some kerns for digits. So, consider this feature not supported +-- till we have a proper test font. + +local function initialize(tfmdata,value) + if value then + local opbd = tfmdata.shared.features.opbd + if opbd then + -- possible values: left right both yes no (experimental) + map_opbd_onto_protrusion(tfmdata,value,opbd) + else + local class, vector = get_class_and_vector(tfmdata,value,"protrusions") + if class then + if vector then + local factor = class.factor or 1 + local left = class.left or 1 + local right = class.right or 1 + if trace_protrusion then + report_protrusions("setting class %a, vector %a, factor %a, left %a, right %a", + value,class.vector,factor,left,right) + end + local data = characters.data + local lfactor = left * factor + local rfactor = right * factor + if trace_protrusion then + report_protrusions("left factor %0.3F, right factor %0.3F",lfactor,rfactor) + end + tfmdata.parameters.protrusion = { + factor = factor, + left = left, + right = right, + } + for i, chr in next, tfmdata.characters do + local v = vector[i] + local pl = nil + local pr = nil + if v then + pl = v[1] + pr = v[2] + else + local d = data[i] + if d then + local s = d.shcode + if not s then + -- sorry + elseif type(s) == "table" then + local vl = vector[s[1]] + local vr = vector[s[#s]] + if vl then pl = vl[1] end + if vr then pr = vr[2] end + else + v = vector[s] + if v then + pl = v[1] + pr = v[2] + end + end + end + end + if pl and pl ~= 0 then + local p = pl * lfactor + chr.leftprotrusion = p + if trace_protrusion then + report_protrusions("left -> %0.3F %C ",p,i) + end + end + if pr and pr ~= 0 then + local p = pr * rfactor + chr.rightprotrusion = p + if trace_protrusion then + report_protrusions("right -> %0.3F %C",p,i) + end + end + end + elseif trace_protrusion then + report_protrusions("unknown vector %a in class %a",class.vector,value) + end + elseif trace_protrusion then + report_protrusions("unknown class %a",value) + end + end + end +end + +local specification = { + name = "protrusion", + description = "l/r margin character protrusion", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end) + +implement { + name = "setupfontprotrusion", + arguments = "2 strings", + actions = function(class,settings) getparameters(classes,class,'preset',settings) end +} + +local function initialize(tfmdata,value) + local properties = tfmdata.properties + local parameters = tfmdata.parameters + if properties then + value = tonumber(value) + if value then + if value < 0 then + value = 0 + elseif value > 10 then + report_expansions("threshold for %a @ %p limited to 10 pct",properties.fontname,parameters.size) + value = 10 + end + if value > 5 then + report_expansions("threshold for %a @ %p exceeds 5 pct",properties.fontname,parameters.size) + end + end + properties.threshold = value or nil -- nil enforces default + end +end + +local specification = { + name = "threshold", + description = "threshold for quality features", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) diff --git a/tex/context/base/mkxl/font-imp-tracing.lmt b/tex/context/base/mkxl/font-imp-tracing.lmt index 9f842b522..2187b9497 100644 --- a/tex/context/base/mkxl/font-imp-tracing.lmt +++ b/tex/context/base/mkxl/font-imp-tracing.lmt @@ -186,7 +186,7 @@ local function initialize(tfmdata,key,value) local tlcolor = { "startcolor", "trace:4" } -- y / dy for unicode, character in next, characters do local mathkern = character.mathkern - local italic = character.vert_italic or character.italic + local italic = character.vitalic or character.italic if mathkern or (italic and italic ~= 0) then local width = character.width or 0 local height = character.height or 0 @@ -202,10 +202,10 @@ local function initialize(tfmdata,key,value) count = count + 1 list[count] = black end if mathkern then - local br = mathkern.bottom_right - local tr = mathkern.top_right - local bl = mathkern.bottom_left - local tl = mathkern.top_left + local br = mathkern.bottomright + local tr = mathkern.topright + local bl = mathkern.bottomleft + local tl = mathkern.topleft if br then local done = false for i=1,#br do diff --git a/tex/context/base/mkxl/font-ini.mklx b/tex/context/base/mkxl/font-ini.mklx index db90bc79c..6a926bcbd 100644 --- a/tex/context/base/mkxl/font-ini.mklx +++ b/tex/context/base/mkxl/font-ini.mklx @@ -703,6 +703,8 @@ \mutable\let\lastrawfontcall \relax \mutable\let\lastglobalrawfontcall\relax +\immutable\dimensiondef\d_font_default_size 10pt + \protected\def\font_helpers_low_level_define {\ifconditional\c_font_compact \expandafter\font_helpers_low_level_define_compact @@ -733,8 +735,10 @@ \fi % \ifcase\scaledfontmode\relax - % none, avoid the designsize if possible - \d_font_scaled_font_size-\plusthousand\scaledpoint + % mkiv, fails with glyphscale: + % \d_font_scaled_font_size-\plusthousand\scaledpoint + % so we just assume + \d_font_scaled_font_size\d_font_default_size \or % at \d_font_scaled_font_size\somefontsize @@ -830,8 +834,10 @@ \fi % \ifcase\scaledfontmode\relax - % none, avoid the designsize if possible - \d_font_scaled_font_size-\plusthousand\scaledpoint + % mkiv, fails with glyphscale: + % \d_font_scaled_font_size-\plusthousand\scaledpoint + % so we just assume + \d_font_scaled_font_size\d_font_default_size \or % at \d_font_scaled_font_size\somefontsize diff --git a/tex/context/base/mkxl/font-lib.mklx b/tex/context/base/mkxl/font-lib.mklx index e8c5ad246..2f20214e7 100644 --- a/tex/context/base/mkxl/font-lib.mklx +++ b/tex/context/base/mkxl/font-lib.mklx @@ -21,30 +21,30 @@ %registerctxluafile{font-cft}{} \registerctxluafile{font-enc}{} \registerctxluafile{font-fmp}{autosuffix} -\registerctxluafile{font-agl}{} % if needed we can comment this and delay loading -\registerctxluafile{font-cid}{} % cid maps +\registerctxluafile{font-agl}{} % if needed we can comment this and delay loading +\registerctxluafile{font-cid}{} % cid maps \registerctxluafile{font-map}{optimize} % helpers -\registerctxluafile{font-otr}{optimize} % opentype fontloader -\registerctxluafile{font-web}{} % opentype fontloader -\registerctxluafile{font-cff}{optimize} % quadratic outlines -\registerctxluafile{font-ttf}{optimize} % cubic outlines -\registerctxluafile{font-dsp}{optimize} % ... for this one -\registerctxluafile{font-hsh}{} % hashes used by context +\registerctxluafile{font-otr}{optimize} % opentype fontloader +\registerctxluafile{font-web}{} % opentype fontloader +\registerctxluafile{font-cff}{optimize} % quadratic outlines +\registerctxluafile{font-ttf}{optimize} % cubic outlines +\registerctxluafile{font-dsp}{optimize} % ... for this one +\registerctxluafile{font-hsh}{autosuffix} % hashes used by context \registerctxluafile{font-vir}{} \registerctxluafile{font-vfc}{autosuffix} -\registerctxluafile{font-prv}{} % needs hashes +\registerctxluafile{font-prv}{} % needs hashes \registerctxluafile{font-nod}{optimize} -\registerctxluafile{font-oti}{} % otf initialization -\registerctxluafile{font-ott}{} % otf tables (first) -\registerctxluafile{font-otl}{} +\registerctxluafile{font-oti}{} % otf initialization +\registerctxluafile{font-ott}{} % otf tables (first) +\registerctxluafile{font-otl}{autosuffix} \registerctxluafile{font-oto}{} \registerctxluafile{font-otj}{autosuffix,optimize} \registerctxluafile{font-oup}{} \registerctxluafile{font-ota}{autosuffix} -% \registerctxluafile{font-ots-pre-scale}{autosuffix,optimize} +%registerctxluafile{font-ots-pre-scale}{autosuffix,optimize} \registerctxluafile{font-ots}{autosuffix,optimize} \registerctxluafile{font-otd}{autosuffix,optimize} \registerctxluafile{font-otc}{} @@ -56,15 +56,15 @@ % we use otf code for type one \registerctxluafile{font-onr}{optimize} -\registerctxluafile{font-one}{optimize} +\registerctxluafile{font-one}{autosuffix,optimize} \registerctxluafile{font-afk}{} \registerctxluafile{font-txt}{autosuffix} % tfm -\registerctxluafile{font-tpk}{optimize} -\registerctxluafile{font-tfm}{} +\registerctxluafile{font-tpk}{autosuffix,optimize} +\registerctxluafile{font-tfm}{autosuffix} % name database @@ -100,13 +100,13 @@ \registerctxluafile{font-imp-ligatures}{} \registerctxluafile{font-imp-tex}{} \registerctxluafile{font-imp-reorder}{} -\registerctxluafile{font-imp-properties}{} +\registerctxluafile{font-imp-properties}{autosuffix} \registerctxluafile{font-imp-unicode}{} \registerctxluafile{font-imp-text}{autosuffix} \registerctxluafile{font-imp-math}{autosuffix} \registerctxluafile{font-imp-notused}{} \registerctxluafile{font-imp-effects}{autosuffix} -\registerctxluafile{font-imp-quality}{} +\registerctxluafile{font-imp-quality}{autosuffix} \registerctxluafile{font-imp-italics}{} \registerctxluafile{font-imp-dimensions}{} \registerctxluafile{font-imp-spacekerns}{} diff --git a/tex/context/base/mkxl/font-one.lmt b/tex/context/base/mkxl/font-one.lmt new file mode 100644 index 000000000..453f61192 --- /dev/null +++ b/tex/context/base/mkxl/font-one.lmt @@ -0,0 +1,847 @@ +if not modules then modules = { } end modules ['font-one'] = { + version = 1.001, + optimize = true, + 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" +} + +--[[ldx-- +<p>Some code may look a bit obscure but this has to do with the fact that we also use +this code for testing and much code evolved in the transition from <l n='tfm'/> to +<l n='afm'/> to <l n='otf'/>.</p> + +<p>The following code still has traces of intermediate font support where we handles +font encodings. Eventually font encoding went away but we kept some code around in +other modules.</p> + +<p>This version implements a node mode approach so that users can also more easily +add features.</p> +--ldx]]-- + +local fonts, logs, trackers, containers, resolvers = fonts, logs, trackers, containers, resolvers + +local next, type, tonumber, rawget = next, type, tonumber, rawget +local match, gsub = string.match, string.gsub +local abs = math.abs +local P, S, R, Cmt, C, Ct, Cs, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg +local lpegmatch, patterns = lpeg.match, lpeg.patterns +local sortedhash = table.sortedhash + +local trace_features = false trackers.register("afm.features", function(v) trace_features = v end) +local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end) +local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end) +local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) + +local report_afm = logs.reporter("fonts","afm loading") + +local setmetatableindex = table.setmetatableindex +local derivetable = table.derive + +local findbinfile = resolvers.findbinfile + +local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF + +local definers = fonts.definers +local readers = fonts.readers +local constructors = fonts.constructors + +local afm = constructors.handlers.afm +local pfb = constructors.handlers.pfb +local otf = fonts.handlers.otf + +local otfreaders = otf.readers +local otfenhancers = otf.enhancers + +local afmfeatures = constructors.features.afm +local registerafmfeature = afmfeatures.register + +local afmenhancers = constructors.enhancers.afm +local registerafmenhancer = afmenhancers.register + +afm.version = 1.513 -- incrementing this number one up will force a re-cache +afm.cache = containers.define("fonts", "one", afm.version, true) +afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*) + +afm.helpdata = { } -- set later on so no local for this +afm.syncspace = true -- when true, nicer stretch values + +local overloads = fonts.mappings.overloads + +local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes + +--[[ldx-- +<p>We cache files. Caching is taken care of in the loader. We cheat a bit by adding +ligatures and kern information to the afm derived data. That way we can set them faster +when defining a font.</p> + +<p>We still keep the loading two phased: first we load the data in a traditional +fashion and later we transform it to sequences. Then we apply some methods also +used in opentype fonts (like <t>tlig</t>).</p> +--ldx]]-- + +function afm.load(filename) + filename = resolvers.findfile(filename,'afm') or "" + if filename ~= "" and not fonts.names.ignoredfile(filename) then + local name = file.removesuffix(file.basename(filename)) + local data = containers.read(afm.cache,name) + local attr = lfs.attributes(filename) + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 + -- + local pfbfile = file.replacesuffix(name,"pfb") + local pfbname = resolvers.findfile(pfbfile,"pfb") or "" + if pfbname == "" then + pfbname = resolvers.findfile(file.basename(pfbfile),"pfb") or "" + end + local pfbsize = 0 + local pfbtime = 0 + if pfbname ~= "" then + local attr = lfs.attributes(pfbname) + pfbsize = attr.size or 0 + pfbtime = attr.modification or 0 + end + if not data or data.size ~= size or data.time ~= time or data.pfbsize ~= pfbsize or data.pfbtime ~= pfbtime then + report_afm("reading %a",filename) + data = afm.readers.loadfont(filename,pfbname) + if data then + afmenhancers.apply(data,filename) + -- otfreaders.addunicodetable(data) -- only when not done yet + fonts.mappings.addtounicode(data,filename) + otfreaders.stripredundant(data) + -- otfreaders.extend(data) + otfreaders.pack(data) + data.size = size + data.time = time + data.pfbsize = pfbsize + data.pfbtime = pfbtime + report_afm("saving %a in cache",name) + -- data.resources.unicodes = nil -- consistent with otf but here we save not much + data = containers.write(afm.cache, name, data) + data = containers.read(afm.cache,name) + end + end + if data then + -- constructors.addcoreunicodes(unicodes) + otfreaders.unpack(data) + otfreaders.expand(data) -- inline tables + otfreaders.addunicodetable(data) -- only when not done yet + otfenhancers.apply(data,filename,data) + if applyruntimefixes then + applyruntimefixes(filename,data) + end + end + return data + end +end + +-- we run a more advanced analyzer later on anyway + +local uparser = fonts.mappings.makenameparser() -- each time + +local function enhance_unify_names(data, filename) + local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context + local unicodes = { } + local names = { } + local private = data.private or privateoffset + local descriptions = data.descriptions + for name, blob in sortedhash(data.characters) do -- sorting is nicer for privates + local code = unicodevector[name] -- or characters.name_to_unicode[name] + if not code then + code = lpegmatch(uparser,name) + if type(code) ~= "number" then + code = private + private = private + 1 + report_afm("assigning private slot %U for unknown glyph name %a",code,name) + end + end + local index = blob.index + unicodes[name] = code + names[name] = index + blob.name = name + descriptions[code] = { + boundingbox = blob.boundingbox, + width = blob.width, + kerns = blob.kerns, + index = index, + name = name, + } + end + for unicode, description in next, descriptions do + local kerns = description.kerns + if kerns then + local krn = { } + for name, kern in next, kerns do + local unicode = unicodes[name] + if unicode then + krn[unicode] = kern + else + -- print(unicode,name) + end + end + description.kerns = krn + end + end + data.characters = nil + data.private = private + local resources = data.resources + local filename = resources.filename or file.removesuffix(file.basename(filename)) + resources.filename = resolvers.unresolve(filename) -- no shortcut + resources.unicodes = unicodes -- name to unicode + resources.marks = { } -- todo + -- resources.names = names -- name to index +end + +local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } +local noflags = { false, false, false, false } + +local function enhance_normalize_features(data) + local ligatures = setmetatableindex("table") + local kerns = setmetatableindex("table") + local extrakerns = setmetatableindex("table") + for u, c in next, data.descriptions do + local l = c.ligatures + local k = c.kerns + local e = c.extrakerns + if l then + ligatures[u] = l + for u, v in next, l do + l[u] = { ligature = v } + end + c.ligatures = nil + end + if k then + kerns[u] = k + for u, v in next, k do + k[u] = v -- { v, 0 } + end + c.kerns = nil + end + if e then + extrakerns[u] = e + for u, v in next, e do + e[u] = v -- { v, 0 } + end + c.extrakerns = nil + end + end + local features = { + gpos = { }, + gsub = { }, + } + local sequences = { + -- only filled ones + } + if next(ligatures) then + features.gsub.liga = everywhere + data.properties.hasligatures = true + sequences[#sequences+1] = { + features = { + liga = everywhere, + }, + flags = noflags, + name = "s_s_0", + nofsteps = 1, + order = { "liga" }, + type = "gsub_ligature", + steps = { + { + coverage = ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern = everywhere + data.properties.haskerns = true + sequences[#sequences+1] = { + features = { + kern = everywhere, + }, + flags = noflags, + name = "p_s_0", + nofsteps = 1, + order = { "kern" }, + type = "gpos_pair", + steps = { + { + format = "kern", + coverage = kerns, + }, + }, + } + end + if next(extrakerns) then + features.gpos.extrakerns = everywhere + data.properties.haskerns = true + sequences[#sequences+1] = { + features = { + extrakerns = everywhere, + }, + flags = noflags, + name = "p_s_1", + nofsteps = 1, + order = { "extrakerns" }, + type = "gpos_pair", + steps = { + { + format = "kern", + coverage = extrakerns, + }, + }, + } + end + -- todo: compress kerns + data.resources.features = features + data.resources.sequences = sequences +end + +local function enhance_fix_names(data) + for k, v in next, data.descriptions do + local n = v.name + local r = overloads[n] + if r then + local name = r.name + if trace_indexing then + report_afm("renaming characters %a to %a",n,name) + end + v.name = name + v.unicode = r.unicode + end + end +end + +--[[ldx-- +<p>These helpers extend the basic table with extra ligatures, texligatures +and extra kerns. This saves quite some lookups later.</p> +--ldx]]-- + +local addthem = function(rawdata,ligatures) + if ligatures then + local descriptions = rawdata.descriptions + local resources = rawdata.resources + local unicodes = resources.unicodes + -- local names = resources.names + for ligname, ligdata in next, ligatures do + local one = descriptions[unicodes[ligname]] + if one then + for _, pair in next, ligdata do + local two = unicodes[pair[1]] + local three = unicodes[pair[2]] + if two and three then + local ol = one.ligatures + if ol then + if not ol[two] then + ol[two] = three + end + else + one.ligatures = { [two] = three } + end + end + end + end + end + end +end + +local function enhance_add_ligatures(rawdata) + addthem(rawdata,afm.helpdata.ligatures) +end + +--[[ldx-- +<p>We keep the extra kerns in separate kerning tables so that we can use +them selectively.</p> +--ldx]]-- + +-- This is rather old code (from the beginning when we had only tfm). If +-- we unify the afm data (now we have names all over the place) then +-- we can use shcodes but there will be many more looping then. But we +-- could get rid of the tables in char-cmp then. Als, in the generic version +-- we don't use the character database. (Ok, we can have a context specific +-- variant). + +local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust here + local descriptions = rawdata.descriptions + local resources = rawdata.resources + local unicodes = resources.unicodes + local function do_it_left(what) + if what then + for unicode, description in next, descriptions do + local kerns = description.kerns + if kerns then + local extrakerns + for complex, simple in next, what do + complex = unicodes[complex] + simple = unicodes[simple] + if complex and simple then + local ks = kerns[simple] + if ks and not kerns[complex] then + if extrakerns then + extrakerns[complex] = ks + else + extrakerns = { [complex] = ks } + end + end + end + end + if extrakerns then + description.extrakerns = extrakerns + end + end + end + end + end + local function do_it_copy(what) + if what then + for complex, simple in next, what do + complex = unicodes[complex] + simple = unicodes[simple] + if complex and simple then + local complexdescription = descriptions[complex] + if complexdescription then -- optional + local simpledescription = descriptions[complex] + if simpledescription then + local extrakerns + local kerns = simpledescription.kerns + if kerns then + for unicode, kern in next, kerns do + if extrakerns then + extrakerns[unicode] = kern + else + extrakerns = { [unicode] = kern } + end + end + end + local extrakerns = simpledescription.extrakerns + if extrakerns then + for unicode, kern in next, extrakerns do + if extrakerns then + extrakerns[unicode] = kern + else + extrakerns = { [unicode] = kern } + end + end + end + if extrakerns then + complexdescription.extrakerns = extrakerns + end + end + end + end + end + end + end + -- add complex with values of simplified when present + do_it_left(afm.helpdata.leftkerned) + do_it_left(afm.helpdata.bothkerned) + -- copy kerns from simple char to complex char unless set + do_it_copy(afm.helpdata.bothkerned) + do_it_copy(afm.helpdata.rightkerned) +end + +--[[ldx-- +<p>The copying routine looks messy (and is indeed a bit messy).</p> +--ldx]]-- + +local function adddimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name + if data then + for unicode, description in next, data.descriptions do + local bb = description.boundingbox + if bb then + local ht = bb[4] + local dp = -bb[2] + if ht == 0 or ht < 0 then + -- no need to set it and no negative heights, nil == 0 + else + description.height = ht + end + if dp == 0 or dp < 0 then + -- no negative depths and no negative depths, nil == 0 + else + description.depth = dp + end + end + end + end +end + +local function copytotfm(data) + if data and data.descriptions then + local metadata = data.metadata + local resources = data.resources + local properties = derivetable(data.properties) + local descriptions = derivetable(data.descriptions) + local goodies = derivetable(data.goodies) + local characters = { } + local parameters = { } + local unicodes = resources.unicodes + -- + for unicode, description in next, data.descriptions do -- use parent table + characters[unicode] = { } + end + -- + local filename = constructors.checkedfilename(resources) + local fontname = metadata.fontname or metadata.fullname + local fullname = metadata.fullname or metadata.fontname + local endash = 0x2013 + local emdash = 0x2014 + local space = 0x0020 -- space + local spacer = "space" + local spaceunits = 500 + -- + local monospaced = metadata.monospaced + local charwidth = metadata.charwidth + local italicangle = metadata.italicangle + local charxheight = metadata.xheight and metadata.xheight > 0 and metadata.xheight + properties.monospaced = monospaced + parameters.italicangle = italicangle + parameters.charwidth = charwidth + parameters.charxheight = charxheight + -- nearly the same as otf, catches + local d_endash = descriptions[endash] + local d_emdash = descriptions[emdash] + local d_space = descriptions[space] + if not d_space or d_space == 0 then + d_space = d_endash + end + if d_space then + spaceunits, spacer = d_space.width or 0, "space" + end + if properties.monospaced then + if spaceunits == 0 and d_emdash then + spaceunits, spacer = d_emdash.width or 0, "emdash" + end + else + if spaceunits == 0 and d_endash then + spaceunits, spacer = d_emdash.width or 0, "endash" + end + end + if spaceunits == 0 and charwidth then + spaceunits, spacer = charwidth or 0, "charwidth" + end + if spaceunits == 0 then + spaceunits = tonumber(spaceunits) or 500 + end + if spaceunits == 0 then + spaceunits = 500 + end + -- + parameters.slant = 0 + parameters.space = spaceunits + parameters.spacestretch = 500 + parameters.spaceshrink = 333 + parameters.xheight = 400 + parameters.quad = 1000 + -- + if italicangle and italicangle ~= 0 then + parameters.italicangle = italicangle + parameters.italicfactor = math.cos(math.rad(90+italicangle)) + parameters.slant = - math.tan(italicangle*math.pi/180) + end + if monospaced then + parameters.spacestretch = 0 + parameters.spaceshrink = 0 + elseif afm.syncspace then + parameters.spacestretch = spaceunits/2 + parameters.spaceshrink = spaceunits/3 + end + parameters.extraspace = parameters.spaceshrink + if charxheight then + parameters.xheight = charxheight + else + -- same as otf + local x = 0x0078 -- x + if x then + local x = descriptions[x] + if x then + parameters.xheight = x.height + end + end + -- + end + -- + if metadata.sup then + local dummy = { 0, 0, 0 } + parameters[ 1] = metadata.designsize or 0 + parameters[ 2] = metadata.checksum or 0 + parameters[ 3], + parameters[ 4], + parameters[ 5] = unpack(metadata.space or dummy) + parameters[ 6] = metadata.quad or 0 + parameters[ 7] = metadata.extraspace or 0 + parameters[ 8], + parameters[ 9], + parameters[10] = unpack(metadata.num or dummy) + parameters[11], + parameters[12] = unpack(metadata.denom or dummy) + parameters[13], + parameters[14], + parameters[15] = unpack(metadata.sup or dummy) + parameters[16], + parameters[17] = unpack(metadata.sub or dummy) + parameters[18] = metadata.supdrop or 0 + parameters[19] = metadata.subdrop or 0 + parameters[20], + parameters[21] = unpack(metadata.delim or dummy) + parameters[22] = metadata.axisheight or 0 + end + -- + parameters.designsize = (metadata.designsize or 10)*65536 + parameters.ascender = abs(metadata.ascender or 0) + parameters.descender = abs(metadata.descender or 0) + parameters.units = 1000 + -- + properties.spacer = spacer + properties.format = fonts.formats[filename] or "type1" + properties.filename = filename + properties.fontname = fontname + properties.fullname = fullname + properties.psname = fullname + properties.name = filename or fullname or fontname + properties.private = properties.private or data.private or privateoffset + -- +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then + properties.encodingbytes = 2 +end + -- + if next(characters) then + return { + characters = characters, + descriptions = descriptions, + parameters = parameters, + resources = resources, + properties = properties, + goodies = goodies, + } + end + end + return nil +end + +--[[ldx-- +<p>Originally we had features kind of hard coded for <l n='afm'/> files but since I +expect to support more font formats, I decided to treat this fontformat like any +other and handle features in a more configurable way.</p> +--ldx]]-- + +function afm.setfeatures(tfmdata,features) + local okay = constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm) + if okay then + return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm) + else + return { } -- will become false + end +end + +local function addtables(data) + local resources = data.resources + local lookuptags = resources.lookuptags + local unicodes = resources.unicodes + if not lookuptags then + lookuptags = { } + resources.lookuptags = lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v = type(k) == "number" and ("lookup " .. k) or k + t[k] = v + return v + end) + if not unicodes then + unicodes = { } + resources.unicodes = unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u, d in next, data.descriptions do + local n = d.name + if n then + t[n] = u + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) -- do we really need this? +end + +local function afmtotfm(specification) + local afmname = specification.filename or specification.name + if specification.forced == "afm" or specification.format == "afm" then -- move this one up + if trace_loading then + report_afm("forcing afm format for %a",afmname) + end + else + local tfmname = findbinfile(afmname,"ofm") or "" + if tfmname ~= "" then + if trace_loading then + report_afm("fallback from afm to tfm for %a",afmname) + end + return -- just that + end + end + if afmname ~= "" then + -- weird, isn't this already done then? + local features = constructors.checkedfeatures("afm",specification.features.normal) + specification.features.normal = features + constructors.hashinstance(specification,true) -- also weird here + -- + specification = definers.resolve(specification) -- new, was forgotten + local cache_id = specification.hash + local tfmdata = containers.read(constructors.cache, cache_id) -- cache with features applied + if not tfmdata then + local rawdata = afm.load(afmname) + if rawdata and next(rawdata) then + addtables(rawdata) + adddimensions(rawdata) + tfmdata = copytotfm(rawdata) + if tfmdata and next(tfmdata) then + local shared = tfmdata.shared + if not shared then + shared = { } + tfmdata.shared = shared + end + shared.rawdata = rawdata + shared.dynamics = { } + tfmdata.changed = { } + shared.features = features + shared.processes = afm.setfeatures(tfmdata,features) + end + elseif trace_loading then + report_afm("no (valid) afm file found with name %a",afmname) + end + tfmdata = containers.write(constructors.cache,cache_id,tfmdata) + end + return tfmdata + end +end + +--[[ldx-- +<p>As soon as we could intercept the <l n='tfm'/> reader, I implemented an +<l n='afm'/> reader. Since traditional <l n='pdftex'/> could use <l n='opentype'/> +fonts with <l n='afm'/> companions, the following method also could handle +those cases, but now that we can handle <l n='opentype'/> directly we no longer +need this features.</p> +--ldx]]-- + +local function read_from_afm(specification) + local tfmdata = afmtotfm(specification) + if tfmdata then + tfmdata.properties.name = specification.name + tfmdata.properties.id = specification.id + tfmdata = constructors.scale(tfmdata, specification) + local allfeatures = tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm) + fonts.loggers.register(tfmdata,'afm',specification) + end + return tfmdata +end + +--[[ldx-- +<p>We have the usual two modes and related features initializers and processors.</p> +--ldx]]-- + +registerafmfeature { + name = "mode", + description = "mode", + initializers = { + base = otf.modeinitializer, + node = otf.modeinitializer, + } +} + +registerafmfeature { + name = "features", + description = "features", + default = true, + initializers = { + node = otf.nodemodeinitializer, + base = otf.basemodeinitializer, + }, + processors = { + node = otf.featuresprocessor, + } +} + +-- readers + +fonts.formats.afm = "type1" +fonts.formats.pfb = "type1" + +local function check_afm(specification,fullname) + local foundname = findbinfile(fullname, 'afm') or "" -- just to be sure + if foundname == "" then + foundname = fonts.names.getfilename(fullname,"afm") or "" + end + if fullname and foundname == "" and afm.autoprefixed then + local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.* + if encoding and shortname and fonts.encodings.known[encoding] then + shortname = findbinfile(shortname,'afm') or "" -- just to be sure + if shortname ~= "" then + foundname = shortname + if trace_defining then + report_afm("stripping encoding prefix from filename %a",afmname) + end + end + end + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "afm" + return read_from_afm(specification) + end +end + +function readers.afm(specification,method) + local fullname = specification.filename or "" + local tfmdata = nil + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + tfmdata = check_afm(specification,specification.name .. "." .. forced) + end + if not tfmdata then + local check_tfm = readers.check_tfm + method = (check_tfm and (method or definers.method or "afm or tfm")) or "afm" + if method == "tfm" then + tfmdata = check_tfm(specification,specification.name) + elseif method == "afm" then + tfmdata = check_afm(specification,specification.name) + elseif method == "tfm or afm" then + tfmdata = check_tfm(specification,specification.name) or check_afm(specification,specification.name) + else -- method == "afm or tfm" or method == "" then + tfmdata = check_afm(specification,specification.name) or check_tfm(specification,specification.name) + end + end + else + tfmdata = check_afm(specification,fullname) + end + return tfmdata +end + +function readers.pfb(specification,method) -- only called when forced + local original = specification.specification + if trace_defining then + report_afm("using afm reader for %a",original) + end + specification.forced = "afm" + local function swap(name) + local value = specification[swap] + if value then + specification[swap] = gsub("%.pfb",".afm",1) + end + end + swap("filename") + swap("fullname") + swap("forcedname") + swap("specification") + return readers.afm(specification,method) +end + +-- now we register them + +registerafmenhancer("unify names", enhance_unify_names) +registerafmenhancer("add ligatures", enhance_add_ligatures) +registerafmenhancer("add extra kerns", enhance_add_extra_kerns) +registerafmenhancer("normalize features", enhance_normalize_features) +registerafmenhancer("check extra features", otfenhancers.enhance) +registerafmenhancer("fix names", enhance_fix_names) diff --git a/tex/context/base/mkxl/font-otl.lmt b/tex/context/base/mkxl/font-otl.lmt new file mode 100644 index 000000000..f493bc327 --- /dev/null +++ b/tex/context/base/mkxl/font-otl.lmt @@ -0,0 +1,889 @@ +if not modules then modules = { } end modules ['font-otl'] = { + 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", +} + +-- After some experimenting with an alternative loader (one that is needed for +-- getting outlines in mp) I decided not to be compatible with the old (built-in) +-- one. The approach used in font-otn is as follows: we load the font in a compact +-- format but still very compatible with the ff data structures. From there we +-- create hashes to access the data efficiently. The implementation of feature +-- processing is mostly based on looking at the data as organized in the glyphs and +-- lookups as well as the specification. Keeping the lookup data in the glyphs is +-- very instructive and handy for tracing. On the other hand hashing is what brings +-- speed. So, the in the new approach (the old one will stay around too) we no +-- longer keep data in the glyphs which saves us a (what in retrospect looks a bit +-- like) a reconstruction step. It also means that the data format of the cached +-- files changes. What method is used depends on that format. There is no fundamental +-- change in processing, and not even in data organation. Most has to do with +-- loading and storage. + +-- todo: less tounicodes + +local lower = string.lower +local type, next, tonumber, tostring, unpack = type, next, tonumber, tostring, unpack +local abs = math.abs +local derivetable, sortedhash = table.derive, table.sortedhash +local formatters = string.formatters + +local setmetatableindex = table.setmetatableindex +local allocate = utilities.storage.allocate +local registertracker = trackers.register +local registerdirective = directives.register +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming +local elapsedtime = statistics.elapsedtime +local findbinfile = resolvers.findbinfile + +----- trace_private = false registertracker("otf.private", function(v) trace_private = v end) +----- trace_subfonts = false registertracker("otf.subfonts", function(v) trace_subfonts = v end) +local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end) +local trace_features = false registertracker("otf.features", function(v) trace_features = v end) +----- trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end) +----- trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end) +----- trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end) +local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end) + +local report_otf = logs.reporter("fonts","otf loading") + +local fonts = fonts +local otf = fonts.handlers.otf + +otf.version = 3.119 -- beware: also sync font-mis.lua and in mtx-fonts +otf.cache = containers.define("fonts", "otl", otf.version, true) +otf.svgcache = containers.define("fonts", "svg", otf.version, true) +otf.pngcache = containers.define("fonts", "png", otf.version, true) +otf.pdfcache = containers.define("fonts", "pdf", otf.version, true) +otf.mpscache = containers.define("fonts", "mps", otf.version, true) + +otf.svgenabled = false +otf.pngenabled = false + +local otfreaders = otf.readers + +local hashes = fonts.hashes +local definers = fonts.definers +local readers = fonts.readers +local constructors = fonts.constructors + +local otffeatures = constructors.features.otf +local registerotffeature = otffeatures.register + +local otfenhancers = constructors.enhancers.otf +local registerotfenhancer = otfenhancers.register + +local forceload = false +local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M) +local syncspace = true +local forcenotdef = false + +local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF + +local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes + +local wildcard = "*" +local default = "dflt" + +local formats = fonts.formats + +formats.otf = "opentype" +formats.ttf = "truetype" +formats.ttc = "truetype" + +registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end) +registerdirective("fonts.otf.loader.force", function(v) forceload = v end) +registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end) +registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end) + +-- otfenhancers.patch("before","migrate metadata","cambria",function() end) + +registerotfenhancer("check extra features", function() end) -- placeholder + +-- Kai has memory problems on osx so here is an experiment (I only tested on windows as +-- my test mac is old and gets no updates and is therefore rather useless.): + +local checkmemory = utilities.lua and utilities.lua.checkmemory +local threshold = 100 -- MB +local tracememory = false + +registertracker("fonts.otf.loader.memory",function(v) tracememory = v end) + +if not checkmemory then -- we need a generic plug (this code might move): + + local collectgarbage = collectgarbage + + checkmemory = function(previous,threshold) -- threshold in MB + local current = collectgarbage("count") + if previous then + local checked = (threshold or 64)*1024 + if current - previous > checked then + collectgarbage("collect") + current = collectgarbage("count") + end + end + return current + end + +end + +function otf.load(filename,sub,instance) + local base = file.basename(file.removesuffix(filename)) + local name = file.removesuffix(base) -- already no suffix + local attr = lfs.attributes(filename) + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 + -- sub can be number of string + if sub == "" then + sub = false + end + local hash = name + if sub then + hash = hash .. "-" .. sub + end + if instance then + hash = hash .. "-" .. instance + end + hash = containers.cleanname(hash) + local data = containers.read(otf.cache,hash) + local reload = not data or data.size ~= size or data.time ~= time or data.tableversion ~= otfreaders.tableversion + if forceload then + report_otf("forced reload of %a due to hard coded flag",filename) + reload = true + end + if reload then + report_otf("loading %a, hash %a",filename,hash) + -- + starttiming(otfreaders,true) + data = otfreaders.loadfont(filename,sub or 1,instance) -- we can pass the number instead (if it comes from a name search) + if data then + -- todo: make this a plugin + local used = checkmemory() + local resources = data.resources + local svgshapes = resources.svgshapes + local pngshapes = resources.pngshapes + if cleanup == 0 then + checkmemory(used,threshold,tracememory) + end + if svgshapes then + resources.svgshapes = nil + if otf.svgenabled then + local timestamp = os.date() + -- work in progress ... a bit boring to do + containers.write(otf.svgcache,hash, { + svgshapes = svgshapes, + timestamp = timestamp, + }) + data.properties.svg = { + hash = hash, + timestamp = timestamp, + } + end + if cleanup > 1 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + end + if pngshapes then + resources.pngshapes = nil + if otf.pngenabled then + local timestamp = os.date() + -- work in progress ... a bit boring to do + containers.write(otf.pngcache,hash, { + pngshapes = pngshapes, + timestamp = timestamp, + }) + data.properties.png = { + hash = hash, + timestamp = timestamp, + } + end + if cleanup > 1 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + end + -- + otfreaders.compact(data) + if cleanup == 0 then + checkmemory(used,threshold,tracememory) + end + otfreaders.rehash(data,"unicodes") + otfreaders.addunicodetable(data) + otfreaders.extend(data) + if cleanup == 0 then + checkmemory(used,threshold,tracememory) + end + if context then + otfreaders.condense(data) + end + otfreaders.pack(data) + report_otf("loading done") + report_otf("saving %a in cache",filename) + data = containers.write(otf.cache, hash, data) + if cleanup > 1 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + stoptiming(otfreaders) + if elapsedtime then + report_otf("loading, optimizing, packing and caching time %s", elapsedtime(otfreaders)) + end + if cleanup > 3 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + data = containers.read(otf.cache,hash) -- this frees the old table and load the sparse one + if cleanup > 2 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + else + stoptiming(otfreaders) + data = nil + report_otf("loading failed due to read error") + end + end + if data then + if trace_defining then + report_otf("loading from cache using hash %a",hash) + end + -- + otfreaders.unpack(data) + otfreaders.expand(data) -- inline tables + otfreaders.addunicodetable(data) -- only when not done yet + -- + otfenhancers.apply(data,filename,data) -- in context one can also use treatments + -- + -- constructors.addcoreunicodes(data.resources.unicodes) -- still needed ? + -- + if applyruntimefixes then + applyruntimefixes(filename,data) -- e.g. see treatments.lfg + end + -- + data.metadata.math = data.resources.mathconstants + -- + -- delayed tables (experiment) + -- + local classes = data.resources.classes + if not classes then + local descriptions = data.descriptions + classes = setmetatableindex(function(t,k) + local d = descriptions[k] + local v = (d and d.class or "base") or false + t[k] = v + return v + end) + data.resources.classes = classes + end + -- + end + + return data +end + +-- modes: node, base, none + +function otf.setfeatures(tfmdata,features) + local okay = constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf) + if okay then + return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf) + else + return { } -- will become false + end +end + +-- the first version made a top/mid/not extensible table, now we just +-- pass on the variants data and deal with it in the tfm scaler (there +-- is no longer an extensible table anyway) +-- +-- we cannot share descriptions as virtual fonts might extend them (ok, +-- we could use a cache with a hash +-- +-- we already assign an empty table to characters as we can add for +-- instance protruding info and loop over characters; one is not supposed +-- to change descriptions and if one does so one should make a copy! + +local function copytotfm(data,cache_id) + if data then + local metadata = data.metadata + local properties = derivetable(data.properties) + local descriptions = derivetable(data.descriptions) + local goodies = derivetable(data.goodies) + local characters = { } -- newtable if we knwo how many + local parameters = { } + local mathparameters = { } + -- + local resources = data.resources + local unicodes = resources.unicodes + local spaceunits = 500 + local spacer = "space" + local designsize = metadata.designsize or 100 + local minsize = metadata.minsize or designsize + local maxsize = metadata.maxsize or designsize + local mathspecs = metadata.math + -- + if designsize == 0 then + designsize = 100 + minsize = 100 + maxsize = 100 + end + if mathspecs then + for name, value in next, mathspecs do + mathparameters[name] = value + end + end + for unicode in next, data.descriptions do -- use parent table + characters[unicode] = { } + end + if mathspecs then + for unicode, character in next, characters do + local d = descriptions[unicode] -- we could use parent table here + local m = d.math + if m then + -- watch out: luatex uses hvariants for the parts + -- + local italic = m.italic + local vitalic = m.vitalic + -- + local variants = m.hvariants + local parts = m.hparts + if variants then + local c = character + for i=1,#variants do + -- local un = variants[i].glyph + local un = variants[i] + c.next = un + c = characters[un] + end -- c is now last in chain + c.hvariants = parts + elseif parts then + character.hvariants = parts + italic = m.hitalic + end + -- + local variants = m.vvariants + local parts = m.vparts + if variants then + local c = character + for i=1,#variants do + -- local un = variants[i].glyph + local un = variants[i] + c.next = un + c = characters[un] + end -- c is now last in chain + c.vvariants = parts + elseif parts then + character.vvariants = parts + end + -- + if italic and italic ~= 0 then + character.italic = italic + end + -- + if vitalic and vitalic ~= 0 then + character.vitalic = vitalic + end + -- + local accent = m.accent -- taccent? + if accent then + character.accent = accent + end + -- + local kerns = m.kerns + if kerns then + character.mathkerns = kerns + end + end + end + end + -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't + -- we use the basename then?) + local filename = constructors.checkedfilename(resources) + local fontname = metadata.fontname + local fullname = metadata.fullname or fontname + local psname = fontname or fullname + local subfont = metadata.subfontindex + local units = metadata.units or 1000 + -- + if units == 0 then -- catch bugs in fonts + units = 1000 -- maybe 2000 when ttf + metadata.units = 1000 + report_otf("changing %a units to %a",0,units) + end + -- + local monospaced = metadata.monospaced + local charwidth = metadata.averagewidth -- or unset + local charxheight = metadata.xheight -- or unset + local italicangle = metadata.italicangle + local hasitalics = metadata.hasitalics + properties.monospaced = monospaced + properties.hasitalics = hasitalics + parameters.italicangle = italicangle + parameters.charwidth = charwidth + parameters.charxheight = charxheight + -- + local space = 0x0020 + local emdash = 0x2014 + if monospaced then + if descriptions[space] then + spaceunits, spacer = descriptions[space].width, "space" + end + if not spaceunits and descriptions[emdash] then + spaceunits, spacer = descriptions[emdash].width, "emdash" + end + if not spaceunits and charwidth then + spaceunits, spacer = charwidth, "charwidth" + end + else + if descriptions[space] then + spaceunits, spacer = descriptions[space].width, "space" + end + if not spaceunits and descriptions[emdash] then + spaceunits, spacer = descriptions[emdash].width/2, "emdash/2" + end + if not spaceunits and charwidth then + spaceunits, spacer = charwidth, "charwidth" + end + end + spaceunits = tonumber(spaceunits) or units/2 + -- + parameters.slant = 0 + parameters.space = spaceunits -- 3.333 (cmr10) + parameters.spacestretch = 1*units/2 -- 500 -- 1.666 (cmr10) + parameters.spaceshrink = 1*units/3 -- 333 -- 1.111 (cmr10) + parameters.xheight = 2*units/5 -- 400 + parameters.quad = units -- 1000 + if spaceunits < 2*units/5 then + -- todo: warning + end + if italicangle and italicangle ~= 0 then + parameters.italicangle = italicangle + parameters.italicfactor = math.cos(math.rad(90+italicangle)) + parameters.slant = - math.tan(italicangle*math.pi/180) + end + if monospaced then + parameters.spacestretch = 0 + parameters.spaceshrink = 0 + elseif syncspace then -- + parameters.spacestretch = spaceunits/2 + parameters.spaceshrink = spaceunits/3 + end + parameters.extraspace = parameters.spaceshrink -- 1.111 (cmr10) + if charxheight then + parameters.xheight = charxheight + else + local x = 0x0078 + if x then + local x = descriptions[x] + if x then + parameters.xheight = x.height + end + end + end + -- + parameters.designsize = (designsize/10)*65536 + parameters.minsize = (minsize /10)*65536 + parameters.maxsize = (maxsize /10)*65536 + parameters.ascender = abs(metadata.ascender or 0) + parameters.descender = abs(metadata.descender or 0) + parameters.units = units + parameters.vheight = metadata.defaultvheight + -- + properties.space = spacer + properties.format = data.format or formats.otf + properties.filename = filename + properties.fontname = fontname + properties.fullname = fullname + properties.psname = psname + properties.name = filename or fullname + properties.subfont = subfont + -- +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then + -- + properties.encodingbytes = 2 +elseif CONTEXTLMTXMODE then + local duplicates = resources and resources.duplicates + if duplicates then + local maxindex = data.nofglyphs or metadata.nofglyphs + if maxindex then + for u, d in sortedhash(duplicates) do + local du = descriptions[u] + if du then + for uu in sortedhash(d) do + maxindex = maxindex + 1 + descriptions[uu].dupindex = du.index + descriptions[uu].index = maxindex + end + else + -- report_otf("no %U in font %a, duplicates ignored",u,filename) + end + end + end + end + -- +end + -- + -- properties.name = specification.name + -- properties.sub = specification.sub + -- + properties.private = properties.private or data.private or privateoffset + -- + return { + characters = characters, + descriptions = descriptions, + parameters = parameters, + mathparameters = mathparameters, + resources = resources, + properties = properties, + goodies = goodies, + } + end +end + +-- These woff files are a kind of joke in a tex environment because one can simply convert +-- them to ttf/otf and use them as such (after all, we cache them too). The successor format +-- woff2 is more complex so there we can as well call an external converter which in the end +-- makes this code kind of obsolete before it's even used. Although ... it might become a +-- more general conversion plug in. + +local converters = { + woff = { + cachename = "webfonts", + action = otf.readers.woff2otf, + } +} + +-- We can get differences between daylight saving etc ... but it makes no sense to +-- mess with trickery .. so be it when you use a different binary. + +local function checkconversion(specification) + local filename = specification.filename + local converter = converters[lower(file.suffix(filename))] + if converter then + local base = file.basename(filename) + local name = file.removesuffix(base) + local attr = lfs.attributes(filename) + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 + if size > 0 then + local cleanname = containers.cleanname(name) + local cachename = caches.setfirstwritablefile(cleanname,converter.cachename) + if not io.exists(cachename) or (time ~= lfs.attributes(cachename).modification) then + report_otf("caching font %a in %a",filename,cachename) + converter.action(filename,cachename) -- todo infoonly + lfs.touch(cachename,time,time) + end + specification.filename = cachename + end + end +end + +local function otftotfm(specification) + local cache_id = specification.hash + local tfmdata = containers.read(constructors.cache,cache_id) + if not tfmdata then + + checkconversion(specification) -- for the moment here + + local name = specification.name + local sub = specification.sub + local subindex = specification.subindex + local filename = specification.filename + local features = specification.features.normal + local instance = specification.instance or (features and features.axis) + local rawdata = otf.load(filename,sub,instance) + if rawdata and next(rawdata) then + local descriptions = rawdata.descriptions + rawdata.lookuphash = { } -- to be done + tfmdata = copytotfm(rawdata,cache_id) + if tfmdata and next(tfmdata) then + -- at this moment no characters are assigned yet, only empty slots + local features = constructors.checkedfeatures("otf",features) + local shared = tfmdata.shared + if not shared then + shared = { } + tfmdata.shared = shared + end + shared.rawdata = rawdata + -- shared.features = features -- default + shared.dynamics = { } + -- shared.processes = { } + tfmdata.changed = { } + shared.features = features + shared.processes = otf.setfeatures(tfmdata,features) + end + end + containers.write(constructors.cache,cache_id,tfmdata) + end + return tfmdata +end + +local function read_from_otf(specification) + local tfmdata = otftotfm(specification) + if tfmdata then + -- this late ? .. needs checking + tfmdata.properties.name = specification.name + tfmdata.properties.sub = specification.sub + tfmdata.properties.id = specification.id + -- + tfmdata = constructors.scale(tfmdata,specification) + local allfeatures = tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf) + constructors.setname(tfmdata,specification) -- only otf? + fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification) + end + return tfmdata +end + +local function checkmathsize(tfmdata,mathsize) + local mathdata = tfmdata.shared.rawdata.metadata.math + local mathsize = tonumber(mathsize) + if mathdata then -- we cannot use mathparameters as luatex will complain + local parameters = tfmdata.parameters + parameters.scriptpercentage = mathdata.ScriptPercentScaleDown + parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown + parameters.mathsize = mathsize -- only when a number ! + end +end + +registerotffeature { + name = "mathsize", + description = "apply mathsize specified in the font", + initializers = { + base = checkmathsize, + node = checkmathsize, + } +} + +-- readers + +function otf.collectlookups(rawdata,kind,script,language) + if not kind then + return + end + if not script then + script = default + end + if not language then + language = default + end + local lookupcache = rawdata.lookupcache + if not lookupcache then + lookupcache = { } + rawdata.lookupcache = lookupcache + end + local kindlookup = lookupcache[kind] + if not kindlookup then + kindlookup = { } + lookupcache[kind] = kindlookup + end + local scriptlookup = kindlookup[script] + if not scriptlookup then + scriptlookup = { } + kindlookup[script] = scriptlookup + end + local languagelookup = scriptlookup[language] + if not languagelookup then + local sequences = rawdata.resources.sequences + local featuremap = { } + local featurelist = { } + if sequences then + for s=1,#sequences do + local sequence = sequences[s] + local features = sequence.features + if features then + features = features[kind] + if features then + -- features = features[script] or features[default] or features[wildcard] + features = features[script] or features[wildcard] + if features then + -- features = features[language] or features[default] or features[wildcard] + features = features[language] or features[wildcard] + if features then + if not featuremap[sequence] then + featuremap[sequence] = true + featurelist[#featurelist+1] = sequence + end + end + end + end + end + end + if #featurelist == 0 then + featuremap, featurelist = false, false + end + else + featuremap, featurelist = false, false + end + languagelookup = { featuremap, featurelist } + scriptlookup[language] = languagelookup + end + return unpack(languagelookup) +end + +-- moved from font-oth.lua, todo: also afm + +local function getgsub(tfmdata,k,kind,value) + local shared = tfmdata.shared + local rawdata = shared and shared.rawdata + if rawdata then + local sequences = rawdata.resources.sequences + if sequences then + local properties = tfmdata.properties + local validlookups, lookuplist = otf.collectlookups(rawdata,kind,properties.script,properties.language) + if validlookups then + -- local choice = tonumber(value) or 1 -- no random here (yet) + for i=1,#lookuplist do + local lookup = lookuplist[i] + local steps = lookup.steps + local nofsteps = lookup.nofsteps + for i=1,nofsteps do + local coverage = steps[i].coverage + if coverage then + local found = coverage[k] + if found then + return found, lookup.type + end + end + end + end + end + end + end +end + +otf.getgsub = getgsub -- returns value, gsub_kind + +function otf.getsubstitution(tfmdata,k,kind,value) + local found, kind = getgsub(tfmdata,k,kind,value) + if not found then + -- + elseif kind == "gsub_single" then + return found + elseif kind == "gsub_alternate" then + local choice = tonumber(value) or 1 -- no random here (yet) + return found[choice] or found[1] or k + end + return k +end + +otf.getalternate = otf.getsubstitution + +function otf.getmultiple(tfmdata,k,kind) + local found, kind = getgsub(tfmdata,k,kind) + if found and kind == "gsub_multiple" then + return found + end + return { k } +end + +function otf.getkern(tfmdata,left,right,kind) + local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub + if kerns then + local found = kerns[right] + local kind = type(found) + if kind == "table" then + found = found[1][3] -- can be more clever + elseif kind ~= "number" then + found = false + end + if found then + return found * tfmdata.parameters.factor + end + end + return 0 +end + +local function check_otf(forced,specification,suffix) + local name = specification.name + if forced then + name = specification.forcedname -- messy + end + local fullname = findbinfile(name,suffix) or "" + if fullname == "" then + fullname = fonts.names.getfilename(name,suffix) or "" + end + if fullname ~= "" and not fonts.names.ignoredfile(fullname) then + specification.filename = fullname + return read_from_otf(specification) + end +end + +local function opentypereader(specification,suffix) + local forced = specification.forced or "" + if formats[forced] then + return check_otf(true,specification,forced) + else + return check_otf(false,specification,suffix) + end +end + +readers.opentype = opentypereader -- kind of useless and obsolete + +function readers.otf(specification) return opentypereader(specification,"otf") end +function readers.ttf(specification) return opentypereader(specification,"ttf") end +function readers.ttc(specification) return opentypereader(specification,"ttf") end + +function readers.woff(specification) + checkconversion(specification) + opentypereader(specification,"") +end + +-- this will be overloaded + +function otf.scriptandlanguage(tfmdata,attr) + local properties = tfmdata.properties + return properties.script or "dflt", properties.language or "dflt" +end + +-- a little bit of abstraction + +local function justset(coverage,unicode,replacement) + coverage[unicode] = replacement +end + +otf.coverup = { + stepkey = "steps", + actions = { + chainsubstitution = justset, + chainposition = justset, + substitution = justset, + alternate = justset, + multiple = justset, + kern = justset, + pair = justset, + single = justset, + ligature = function(coverage,unicode,ligature) + local first = ligature[1] + local tree = coverage[first] + if not tree then + tree = { } + coverage[first] = tree + end + for i=2,#ligature do + local l = ligature[i] + local t = tree[l] + if not t then + t = { } + tree[l] = t + end + tree = t + end + tree.ligature = unicode + end, + }, + register = function(coverage,featuretype,format) + return { + format = format, + coverage = coverage, + } + end +} diff --git a/tex/context/base/mkxl/font-tfm.lmt b/tex/context/base/mkxl/font-tfm.lmt new file mode 100644 index 000000000..dcb76ba80 --- /dev/null +++ b/tex/context/base/mkxl/font-tfm.lmt @@ -0,0 +1,666 @@ +if not modules then modules = { } end modules ['font-tfm'] = { + 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 end -- use luatex-fonts-tfm.lua instead + +local next, type = next, type +local match, format = string.match, string.format +local concat, sortedhash = table.concat, table.sortedhash +local idiv = number.idiv + +local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) +local trace_features = false trackers.register("tfm.features", function(v) trace_features = v end) + +local report_defining = logs.reporter("fonts","defining") +local report_tfm = logs.reporter("fonts","tfm loading") + +local findbinfile = resolvers.findbinfile +local setmetatableindex = table.setmetatableindex + +local fonts = fonts +local handlers = fonts.handlers +local helpers = fonts.helpers +local readers = fonts.readers +local constructors = fonts.constructors +local encodings = fonts.encodings + +local tfm = constructors.handlers.tfm +tfm.version = 1.000 +tfm.maxnestingdepth = 5 +tfm.maxnestingsize = 65536*1024 + +local otf = fonts.handlers.otf +local otfenhancers = otf.enhancers + +local tfmfeatures = constructors.features.tfm +local registertfmfeature = tfmfeatures.register + +local tfmenhancers = constructors.enhancers.tfm +local registertfmenhancer = tfmenhancers.register + +local charcommand = helpers.commands.char + +constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua + +fonts.formats.tfm = "type1" -- we need to have at least a value here +fonts.formats.ofm = "type1" -- we need to have at least a value here + +--[[ldx-- +<p>The next function encapsulates the standard <l n='tfm'/> loader as +supplied by <l n='luatex'/>.</p> +--ldx]]-- + +-- this might change: not scaling and then apply features and do scaling in the +-- usual way with dummy descriptions but on the other hand .. we no longer use +-- tfm so why bother + +-- ofm directive blocks local path search unless set; btw, in context we +-- don't support ofm files anyway as this format is obsolete + +-- we need to deal with nested virtual fonts, but because we load in the +-- frontend we also need to make sure we don't nest too deep (esp when sizes +-- get large) +-- +-- (VTITLE Example of a recursion) +-- (MAPFONT D 0 (FONTNAME recurse)(FONTAT D 2)) +-- (CHARACTER C A (CHARWD D 1)(CHARHT D 1)(MAP (SETRULE D 1 D 1))) +-- (CHARACTER C B (CHARWD D 2)(CHARHT D 2)(MAP (SETCHAR C A))) +-- (CHARACTER C C (CHARWD D 4)(CHARHT D 4)(MAP (SETCHAR C B))) +-- +-- we added the same checks as below to the luatex engine + +function tfm.setfeatures(tfmdata,features) + local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) + if okay then + return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm) + else + return { } -- will become false + end +end + +local depth = { } -- table.setmetatableindex("number") + +-- Normally we just load the tfm data and go on. However there was some demand for +-- loading good old tfm /pfb files where afm files were lacking and even enc files +-- of dubious quality so we now support loading such (often messy) setups too. +-- +-- Because such fonts also use (ugly) tweaks achieve some purpose (like swapping +-- accents) we need to delay the unicoding actions till after the features have been +-- applied. +-- +-- It must be noted that in ConTeXt we don't expect this to be used at all. Here is +-- example: +-- +-- tfm metrics + pfb vector for index + pfb file for shapes +-- +-- \font\foo=file:csr10.tfm:reencode=auto;mode=node;liga=yes;kern=yes +-- +-- tfm metrics + pfb vector for index + enc file for tfm mapping + pfb file for shapes +-- +-- \font\foo=file:csr10.tfm:reencode=csr.enc;mode=node;liga=yes;kern=yes +-- +-- tfm metrics + enc file for mapping to tfm + bitmaps shapes +-- +-- \font\foo=file:csr10.tfm:reencode=csr.enc;bitmap=yes;mode=node;liga=yes;kern=yes +-- +-- One can add features: +-- +-- fonts.handlers.otf.addfeature { +-- name = "czechdqcheat", +-- type = "substitution", +-- data = { +-- quotedblright = "csquotedblright", +-- }, +-- } +-- +-- So "czechdqcheat=yes" is then a valid feature. And yes, it's a cheat. + +local loadtfmvf = tfm.readers.loadtfmvf + +local function read_from_tfm(specification) + local filename = specification.filename + local size = specification.size + depth[filename] = (depth[filename] or 0) + 1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata = loadtfmvf(filename,size) + if tfmdata then + + local features = specification.features and specification.features.normal or { } + local features = constructors.checkedfeatures("tfm",features) + specification.features.normal = features + + -- If reencode returns a new table, we assume that we're doing something + -- special. An 'auto' reencode picks up its vector from the pfb file. + + local getmapentry = fonts.mappings.getentry + + if getmapentry and not features.reencode then + -- This can happen multiple times but not that often so we don't + -- optimize this. + local encoding, pfbfile, encfile = getmapentry(filename) + if encoding and pfbfile then + features.reencode = encfile + features.pfbfile = pfbfile + end + end + local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata = newtfmdata + end + + local resources = tfmdata.resources or { } + local properties = tfmdata.properties or { } + local parameters = tfmdata.parameters or { } + local shared = tfmdata.shared or { } + -- + shared.features = features + shared.resources = resources + -- + properties.id = specification.id + properties.name = tfmdata.name -- todo: fallback + properties.fontname = tfmdata.fontname -- todo: fallback + properties.psname = tfmdata.psname -- todo: fallback + properties.fullname = tfmdata.fullname -- todo: fallback + properties.filename = specification.filename -- todo: fallback + properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing + properties.usedbitmap = tfmdata.usedbitmap + -- + if getmapentry and newtfmdata then + properties.filename = features.pfbfile + end + -- + tfmdata.properties = properties + tfmdata.resources = resources + tfmdata.parameters = parameters + tfmdata.shared = shared + -- + shared.rawdata = { resources = resources } + shared.features = features + -- + -- The next branch is only entered when we have a proper encoded file i.e. + -- unicodes and such. It really nakes no sense to do feature juggling when + -- we have no names and unicodes. + -- + if newtfmdata then + -- + -- Some opentype processing assumes these to be present: + -- + if not resources.marks then + resources.marks = { } + end + if not resources.sequences then + resources.sequences = { } + end + if not resources.features then + resources.features = { + gsub = { }, + gpos = { }, + } + end + if not tfmdata.changed then + tfmdata.changed = { } + end + if not tfmdata.descriptions then + tfmdata.descriptions = tfmdata.characters + end + -- + -- It might be handy to have this: + -- + otf.readers.addunicodetable(tfmdata) + -- + -- We make a pseudo opentype font, e.g. kerns and ligatures etc: + -- + tfmenhancers.apply(tfmdata,filename) + -- + -- Now user stuff can kick in. + -- + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + -- + -- As that can also mess with names and such, we are now ready for finalizing + -- the unicode information. This is a different order that for instance type one + -- (afm) files. First we try to deduce unicodes from already present information. + -- + otf.readers.unifymissing(tfmdata) + -- + -- Next we fill in the gaps, based on names from teh agl. Probably not much will + -- happen here. + -- + fonts.mappings.addtounicode(tfmdata,filename) + -- + -- The tounicode data is passed to the backend that constructs the vectors for us. + -- +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then + tfmdata.tounicode = 1 +end + local tounicode = fonts.mappings.tounicode + for unicode, v in next, tfmdata.characters do + local u = v.unicode + if u then + v.tounicode = tounicode(u) + end + end + -- + -- However, when we use a bitmap font those vectors can't be constructed because + -- that information is not carried with those fonts (there is no name info, nor + -- proper index info, nor unicodes at that end). So, we provide it ourselves. + -- + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + -- + shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil + -- + if size < 0 then + size = idiv(65536 * -size,100) + end + + parameters.factor = 1 -- already scaled + parameters.units = 1000 -- just in case + parameters.size = size + parameters.slant = parameters.slant or parameters[1] or 0 + parameters.space = parameters.space or parameters[2] or 0 + parameters.spacestretch = parameters.spacestretch or parameters[3] or 0 + parameters.spaceshrink = parameters.spaceshrink or parameters[4] or 0 + parameters.xheight = parameters.xheight or parameters[5] or 0 + parameters.quad = parameters.quad or parameters[6] or 0 + parameters.extraspace = parameters.extraspace or parameters[7] or 0 + -- + constructors.enhanceparameters(parameters) -- official copies for us + -- + properties.private = properties.private or tfmdata.private or privateoffset + -- + if newtfmdata then + -- + -- We do nothing as we assume flat tfm files. It would become real messy + -- otherwise and I don't have something for testing on my system anyway. + -- + else + -- already loaded + local fonts = tfmdata.fonts + if fonts then + for i=1,#fonts do + local font = fonts[i] + local id = font.id + if not id then + local name = font.name + local size = font.size + if name and size then + local data, id = constructors.readanddefine(name,size) + if id then + font.id = id + font.name = nil + font.size = nil + end + end + end + end + end + end + -- + properties.haskerns = true + properties.hasligatures = true + properties.hasitalics = true + resources.unicodes = { } + resources.lookuptags = { } + -- + depth[filename] = depth[filename] - 1 + -- + return tfmdata + else + depth[filename] = depth[filename] - 1 + end +end + +local function check_tfm(specification,fullname) -- we could split up like afm/otf + local foundname = findbinfile(fullname, 'tfm') or "" + if foundname == "" then + foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context + end + if foundname == "" then + foundname = fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) + end +end + +readers.check_tfm = check_tfm + +function readers.tfm(specification) + local fullname = specification.filename or "" + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + fullname = specification.name .. "." .. forced + else + fullname = specification.name + end + end + return check_tfm(specification,fullname) +end + +readers.ofm = readers.tfm + +-- The reencoding acts upon the 'reencode' feature which can have values 'auto' or +-- an enc file. You can also specify a 'pfbfile' feature (but it defaults to the +-- tfm filename) and a 'bitmap' feature. When no enc file is givven (auto) we will +-- get the vectors from the pfb file. + +do + + local outfiles = { } + + local tfmcache = table.setmetatableindex(function(t,tfmdata) + local id = font.define(tfmdata) + t[tfmdata] = id + return id + end) + + local encdone = table.setmetatableindex("table") + + function tfm.reencode(tfmdata,specification) + + local features = specification.features + + if not features then + return + end + + local features = features.normal + + if not features then + return + end + + local tfmfile = file.basename(tfmdata.name) + local encfile = features.reencode -- or features.enc + local pfbfile = features.pfbfile -- or features.pfb + local bitmap = features.bitmap -- or features.pk + + if not encfile then + return + end + + local pfbfile = pfbfile or outfiles[tfmfile] + + if pfbfile == nil then + if bitmap then + pfbfile = false + elseif type(pfbfile) ~= "string" then + pfbfile = tfmfile + end + if type(pfbfile) == "string" then + pfbfile = file.addsuffix(pfbfile,"pfb") + -- pdf.mapline(tfmfile .. "<" .. pfbfile) + report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile) + else + report_tfm("using bitmap shapes for %a",tfmfile) + pfbfile = false -- use bitmap + end + outfiles[tfmfile] = pfbfile + end + + local encoding = false + local vector = false + if type(pfbfile) == "string" then + local pfb = constructors.handlers.pfb + if pfb and pfb.loadvector then + local v, e = pfb.loadvector(pfbfile) + if v then + vector = v + end + if e then + encoding = e + end + end + end + if type(encfile) == "string" and encfile ~= "auto" then + encoding = fonts.encodings.load(file.addsuffix(encfile,"enc")) + if encoding then + encoding = encoding.vector + end + end + if not encoding then + report_tfm("bad encoding for %a, quitting",tfmfile) + return + end + + local unicoding = fonts.encodings.agl and fonts.encodings.agl.unicodes + local virtualid = tfmcache[tfmdata] + local tfmdata = table.copy(tfmdata) -- good enough for small fonts + local characters = { } + local originals = tfmdata.characters + local indices = { } + local parentfont = { "font", 1 } -- can be zero (self referencing) + local private = tfmdata.privateoffset or constructors.privateoffset + local reported = encdone[tfmfile][encfile] -- bah, encdone for tfm or pfb ? + -- create characters table + + -- vector : pfbindex -> name + -- encoding : tfmindex -> name + + -- we store the order also because some tex encodings (see math-vfu) needs + -- that for remapping with non standard glyphs names cq. lack of unicode + -- slot information + + for k, v in next, originals do + v.order = k + end + + local backmap = vector and table.swapped(vector) + local done = { } -- prevent duplicate + for tfmindex, name in sortedhash(encoding) do -- predictable order + local original = originals[tfmindex] + if original then + local unicode = unicoding[name] + if unicode then + original.unicode = unicode + else + unicode = private + private = private + 1 + if trace_defining and not reported then + report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode) + end + end + characters[unicode] = original + indices[tfmindex] = unicode + original.name = name -- so one can lookup weird names + if backmap then + original.index = backmap[name] -- the pfb index + else -- probably bitmap + original.commands = { parentfont, charcommand[tfmindex] } -- or "slot" + original.oindex = tfmindex + end + done[name] = true + elseif not done[name] then + report_tfm("bad index %a in font %a with name %a",tfmindex,tfmfile,name) + end + end + + encdone[tfmfile][encfile] = true + + -- redo kerns and ligatures + + for k, v in next, characters do + local kerns = v.kerns + if kerns then + local t = { } + for k, v in next, kerns do + local i = indices[k] + if i then + t[i] = v + end + end + v.kerns = next(t) and t or nil + end + local ligatures = v.ligatures + if ligatures then + local t = { } + for k, v in next, ligatures do + local i = indices[k] + if i then + t[i] = v + v.char = indices[v.char] + end + end + v.ligatures = next(t) and t or nil + end + end + + -- wrap up + + tfmdata.fonts = { { id = virtualid } } + tfmdata.characters = characters + tfmdata.fullname = tfmdata.fullname or tfmdata.name + tfmdata.psname = file.nameonly(pfbfile or tfmdata.name) + tfmdata.filename = pfbfile + -- tfmdata.format = bitmap and "type3" or "type1" + tfmdata.format = "type1" +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then + tfmdata.encodingbytes = 2 + tfmdata.tounicode = 1 + tfmdata.embedding = "subset" +end + tfmdata.usedbitmap = bitmap and virtualid + tfmdata.private = private + + return tfmdata + end + +end + +-- Now we implement the regular features handlers. We need to convert the +-- tfm specific structures to opentype structures. In basemode they are +-- converted back so that is a bit of a waste but it's fast enough. + +do + + local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } + local noflags = { false, false, false, false } + + local function enhance_normalize_features(data) + local ligatures = setmetatableindex("table") + local kerns = setmetatableindex("table") + local characters = data.characters + for u, c in next, characters do + local l = c.ligatures + local k = c.kerns + if l then + ligatures[u] = l + for u, v in next, l do + l[u] = { ligature = v.char } + end + c.ligatures = nil + end + if k then + kerns[u] = k + for u, v in next, k do + k[u] = v -- { v, 0 } + end + c.kerns = nil + end + end + + for u, l in next, ligatures do + for k, v in next, l do + local vl = v.ligature + local dl = ligatures[vl] + if dl then + for kk, vv in next, dl do + v[kk] = vv -- table.copy(vv) + end + end + end + end + + local features = { + gpos = { }, + gsub = { }, + } + local sequences = { + -- only filled ones + } + if next(ligatures) then + features.gsub.liga = everywhere + data.properties.hasligatures = true + sequences[#sequences+1] = { + features = { + liga = everywhere, + }, + flags = noflags, + name = "s_s_0", + nofsteps = 1, + order = { "liga" }, + type = "gsub_ligature", + steps = { + { + coverage = ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern = everywhere + data.properties.haskerns = true + sequences[#sequences+1] = { + features = { + kern = everywhere, + }, + flags = noflags, + name = "p_s_0", + nofsteps = 1, + order = { "kern" }, + type = "gpos_pair", + steps = { + { + format = "kern", + coverage = kerns, + }, + }, + } + end + data.resources.features = features + data.resources.sequences = sequences + data.shared.resources = data.shared.resources or resources + end + + registertfmenhancer("normalize features", enhance_normalize_features) + registertfmenhancer("check extra features", otfenhancers.enhance) + +end + +-- As with type one (afm) loading, we just use the opentype ones: + +registertfmfeature { + name = "mode", + description = "mode", + initializers = { + base = otf.modeinitializer, + node = otf.modeinitializer, + } +} + +registertfmfeature { + name = "features", + description = "features", + default = true, + initializers = { + base = otf.basemodeinitializer, + node = otf.nodemodeinitializer, + }, + processors = { + node = otf.featuresprocessor, + } +} diff --git a/tex/context/base/mkxl/font-tpk.lmt b/tex/context/base/mkxl/font-tpk.lmt new file mode 100644 index 000000000..d216bc257 --- /dev/null +++ b/tex/context/base/mkxl/font-tpk.lmt @@ -0,0 +1,1304 @@ +if not modules then modules = { } end modules ['font-tpk'] = { + version = 1.001, + optimize = true, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The bitmap loader is more or less derived from the luatex version (taco) +-- which is derived from pdftex (thanh) who uses code from dvips (thomas) +-- adapted by piet ... etc. The tfm and vf readers are also derived from +-- luatex. All do things a bit more luaish and errors are of course mine. + +local next = next +local extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift +local idiv = number.idiv +local char = string.char +local concat, insert, remove, copy = table.concat, table.insert, table.remove, table.copy +local tobitstring = number.tobitstring +local formatters = string.formatters +local round = math.round + +local streams = utilities.streams +local openstream = streams.open +local streamsize = streams.size +local readcardinal1 = streams.readcardinal1 +local readcardinal2 = streams.readcardinal2 +local readcardinal3 = streams.readcardinal3 +local readcardinal4 = streams.readcardinal4 +local readinteger1 = streams.readinteger1 +local readinteger2 = streams.readinteger2 +local readinteger3 = streams.readinteger3 +local readinteger4 = streams.readinteger4 +local readbyte = streams.readbyte +local readbytes = streams.readbytes +local readstring = streams.readstring +local skipbytes = streams.skipbytes +local getposition = streams.getposition +local setposition = streams.setposition + +if not fonts then fonts = { handlers = { tfm = { } } } end + +local handlers = fonts.handlers +local tfm = handlers.tfm or { } +handlers.tfm = tfm +local readers = tfm.readers or { } +tfm.readers = readers + +tfm.version = 1.005 +tfm.cache = containers.define("fonts", "tfm", tfm.version, true) + +-- Performance is no real issue here so I didn't optimize too much. After +-- all, these files are small and we mostly use opentype or type1 fonts. + +do + + local function readbitmap(glyph,s,flagbyte) + + local inputbyte = 0 + local bitweight = 0 + local dynf = 0 + local remainder = 0 + local realfunc = nil + local repeatcount = 0 + + local function getnyb() -- can be inlined + if bitweight == 0 then + bitweight = 16 + inputbyte = readbyte(s) + return extract(inputbyte,4,4) + else + bitweight = 0 + return band(inputbyte,15) + end + end + + local function getbit() -- can be inlined + bitweight = rshift(bitweight,1) + if bitweight == 0 then -- actually we can check for 1 + inputbyte = readbyte(s) + bitweight = 128 + end + return band(inputbyte,bitweight) + end + + local function pkpackednum() + local i = getnyb(s) + if i == 0 then + repeat + j = getnyb() + i = i + 1 + until (j ~= 0) + if i > 3 then + return handlehuge(i,j) + else + for i=1,i do + j = j * 16 + getnyb() + end + return j - 15 + (13 - dynf) * 16 + dynf + end + elseif i <= dynf then + return i + elseif i < 14 then + return (i - dynf - 1) * 16 + getnyb() + dynf + 1 + elseif i == 14 then + repeatcount = pkpackednum() + else + repeatcount = 1 + end + return realfunc() + end + + local function rest() + if remainder < 0 then + remainder = -remainder + return 0 + elseif remainder > 4000 then + remainder = 4000 - remainder + return 4000 + elseif remainder > 0 then + local i = remainder + remainder = 0 + realfunc = pkpackednum + return i + else + -- error = "pk issue that shouldn't happen" + return 0 + end + end + + local function handlehuge(i,j) + while i ~= 0 do + j = lshift(j,4) + getnyb() + -- j = extract(j,8,4) + getnyb() + i = i - 1 + end + remainder = j - 15 + (13 - dynf) * 16 + dynf + realfunc = rest + return rest() + end + + local gpower = { [0] = + 0, 1, 3, 7, 15, 31, 63, 127, + 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535 + } + + local raster = { } + local r = 0 + glyph.stream = raster + + local xsize = glyph.xsize + local ysize = glyph.ysize + local word = 0 + local wordweight = 0 + local wordwidth = idiv(xsize + 15,16) + local rowsleft = 0 + local turnon = band(flagbyte,8) == 8 and true or false + local hbit = 0 + local count = 0 + -- + realfunc = pkpackednum + dynf = idiv(flagbyte,16) + -- + if dynf == 14 then + bitweight = 0 + for i=1,ysize do + word = 0 + wordweight = 32768 + for j=1,xsize do + if getbit() ~= 0 then + word = word + wordweight + end + wordweight = rshift(wordweight,1) + if wordweight == 0 then + r = r + 1 + raster[r] = word + word = 0 + wordweight = 32768 + end + end + if wordweight ~= 32768 then + r = r + 1 + raster[r] = word + end + end + else + rowsleft = ysize + hbit = xsize + repeatcount = 0 + wordweight = 16 + word = 0 + bitweight = 0 + while rowsleft > 0 do + count = realfunc() + while count ~= 0 do + if count < wordweight and count < hbit then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - count] + end + hbit = hbit - count + wordweight = wordweight - count + count = 0 + elseif count >= hbit and hbit <= wordweight then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - hbit] + end + r = r + 1 + raster[r] = word + for i=1,repeatcount*wordwidth do + r = r + 1 + raster[r] = raster[r - wordwidth] + end + rowsleft = rowsleft - repeatcount - 1 + repeatcount = 0 + word = 0 + wordweight = 16 + count = count - hbit + hbit = xsize + else + if turnon then + word = word + gpower[wordweight] + end + r = r + 1 + raster[r] = word + word = 0 + count = count - wordweight + hbit = hbit - wordweight + wordweight = 16 + end + end + turnon = not turnon + end + if rowsleft ~= 0 or hbit ~= xsize then + print("ERROR",rowsleft,hbit,xsize) + -- error = "error while unpacking, more bits than required" + end + end + + end + + function readers.showpk(glyph) + local xsize = glyph.xsize + local ysize = glyph.ysize + local stream = glyph.stream + local result = { } + local rr = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + r = 0 + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; rr[r] = tobitstring(b,16,16) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; rr[r] = tobitstring(b,16,16) + else + r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw) + end + result[y] = concat(rr) + end + return concat(result,"\n") + end + + local template = formatters [ [[ +%.3N 0 %i %i %i %i d1 +q +%i 0 0 %i %i %i cm +BI + /W %i + /H %i + /IM true + /BPC 1 + /D [1 0] +ID %t +EI +Q]] ] + + function readers.pktopdf(glyph,data,factor) + local width = data.width * factor + local xsize = glyph.xsize or 0 + local ysize = glyph.ysize or 0 + local xoffset = glyph.xoffset or 0 + local yoffset = glyph.yoffset or 0 + local stream = glyph.stream + + local dpi = 1 + local newdpi = 1 + + local xdpi = dpi * xsize / newdpi + local ydpi = dpi * ysize / newdpi + + local llx = - xoffset + local lly = yoffset - ysize + 1 + local urx = llx + xsize + 1 + local ury = lly + ysize + + local result = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + else + r = r + 1 ; result[r] = char(extract(b,8,8)) + end + end + return template(width,llx,lly,urx,ury,xdpi,ydpi,llx,lly,xsize,ysize,result), width + end + + function readers.loadpk(filename) + local s = openstream(filename) + local preamble = readcardinal1(s) + local version = readcardinal1(s) + local comment = readstring(s,readcardinal1(s)) + local designsize = readcardinal4(s) + local checksum = readcardinal4(s) + local hppp = readcardinal4(s) + local vppp = readcardinal4(s) + if preamble ~= 247 or version ~= 89 or not vppp then + return { error = "invalid preamble" } + end + local glyphs = { } + local data = { + designsize = designsize, + comment = comment, + hppp = hppp, + vppp = vppp, + glyphs = glyphs, + } + while true do + local flagbyte = readcardinal1(s) + if flagbyte < 240 then + local c = band(flagbyte,7) + local length, index, width, pixels, xsize, ysize, xoffset, yoffset + if c >= 0 and c <= 3 then + length = band(flagbyte,7) * 256 + readcardinal1(s) - 3 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal1(s) + xsize = readcardinal1(s) + ysize = readcardinal1(s) + xoffset = readcardinal1(s) + yoffset = readcardinal1(s) + if xoffset > 127 then + xoffset = xoffset - 256 + end + if yoffset > 127 then + yoffset = yoffset - 256 + end + elseif c >= 4 and c <= 6 then + length = band(flagbyte,3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal2(s) + xsize = readcardinal2(s) + ysize = readcardinal2(s) + xoffset = readcardinal2(s) + yoffset = readcardinal2(s) + else -- 7 + length = readcardinal4(s) - 9 + index = readcardinal4(s) + width = readinteger4(s) + pixels = readcardinal4(s) + readcardinal4(s) + xsize = readcardinal4(s) + ysize = readcardinal4(s) + xoffset = readcardinal4(s) + yoffset = readcardinal4(s) + end + local glyph = { + index = index, + width = width, + pixels = pixels, + xsize = xsize, + ysize = ysize, + xoffset = xoffset, + yoffset = yoffset, + } + if length <= 0 then + data.error = "bad packet" + return data + end + readbitmap(glyph,s,flagbyte) + glyphs[index] = glyph + elseif flagbyte == 240 then + -- k[1] x[k] + skipbytes(s,readcardinal1(s)) + elseif flagbyte == 241 then + -- k[2] x[k] + skipbytes(s,readcardinal2(s)*2) + elseif flagbyte == 242 then + -- k[3] x[k] + skipbytes(s,readcardinal3(s)*3) + elseif flagbyte == 243 then + -- k[4] x[k] + skipbytes(s,readcardinal4(s)*4) -- readinteger4 + elseif flagbyte == 244 then + -- y[4] + skipbytes(s,4) + elseif flagbyte == 245 then + break + elseif flagbyte == 246 then + -- nop + else + data.error = "unknown pk command" + break + end + end + return data + end + +end + +do + + local leftboundary = -1 + local rightboundary = -2 + local boundarychar = 65536 + + function readers.loadtfm(filename) + local data + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + local s = openstream(filename) + if not s then + return someerror() + end + -- + local wide = false + local header = 0 + local max = 0 + local size = streamsize(s) + local glyphs = table.setmetatableindex(function(t,k) + local v = { + -- we default because boundary chars have no dimension s + width = 0, + height = 0, + depth = 0, + italic = 0, + } + t[k] = v + return v + end) + local parameters = { } + local direction = 0 + -- + local lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np + -- + lf = readcardinal2(s) + if lf ~= 0 then + header = 6 + max = 255 + wide = false + lh = readcardinal2(s) + bc = readcardinal2(s) + ec = readcardinal2(s) + nw = readcardinal2(s) + nh = readcardinal2(s) + nd = readcardinal2(s) + ni = readcardinal2(s) + nl = readcardinal2(s) + nk = readcardinal2(s) + ne = readcardinal2(s) + np = readcardinal2(s) + else + header = 14 + max = 65535 + wide = readcardinal4(s) == 0 + if not wide then + return someerror("invalid format") + end + lf = readcardinal4(s) + lh = readcardinal4(s) + bc = readcardinal4(s) + ec = readcardinal4(s) + nw = readcardinal4(s) + nh = readcardinal4(s) + nd = readcardinal4(s) + ni = readcardinal4(s) + nl = readcardinal4(s) + nk = readcardinal4(s) + ne = readcardinal4(s) + np = readcardinal4(s) + direction = readcardinal4(s) + end + if (bc > ec + 1) or (ec > max) then + return someerror("file is too small") + end + if bc > max then + bc, ec = 1, 0 + end + local nlw = (wide and 2 or 1) * nl + local neew = (wide and 2 or 1) * ne + local ncw = (wide and 2 or 1) * (ec - bc + 1) + if lf ~= (header + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np) then + return someerror("file is too small") + end + if nw == 0 or nh == 0 or nd == 0 or ni == 0 then + return someerror("no glyphs") + end + if lf * 4 > size then + return someerror("file is too small") + end + local slh = lh + if lh < 2 then + return someerror("file is too small") + end + local checksum = readcardinal4(s) + local designsize = readcardinal2(s) + designsize = designsize * 256 + readcardinal1(s) + designsize = designsize * 16 + rshift(readcardinal1(s),4) + if designsize < 0xFFFF then + return someerror("weird designsize") + end + -- + local alpha = 16 + local z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + local beta = idiv(256,alpha) + alpha = alpha * z + -- + local function readscaled() + local a, b, c, d = readbytes(s,4) + local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta) + if a == 0 then + return n + elseif a == 255 then + return n - alpha + else + return 0 + end + end + -- + local function readunscaled() + local a, b, c, d = readbytes(s,4) + if a > 127 then + a = a - 256 + end + return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4) + end + -- + while lh > 2 do -- can be one-liner + skipbytes(s,4) + lh = lh - 1 + end + local saved = getposition(s) + setposition(s,(header + slh + ncw) * 4 + 1) + local widths = { } for i=0,nw-1 do widths [i] = readscaled() end + local heights = { } for i=0,nh-1 do heights[i] = readscaled() end + local depths = { } for i=0,nd-1 do depths [i] = readscaled() end + local italics = { } for i=0,ni-1 do italics[i] = readscaled() end + if widths[0] ~= 0 or heights[0] ~= 0 or depths[0] ~= 0 then + return someerror("invalid dimensions") + end + -- + local blabel = nl + local bchar = boundarychar + -- + local ligatures = { } + if nl > 0 then + for i=0,nl-1 do + local a, b, c, d = readbytes(s,4) + ligatures[i] = { + skip = a, + nxt = b, + op = c, + rem = d, + } + if a > 128 then + if 256 * c + d >= nl then + return someerror("invalid ligature table") + end + if a == 255 and i == 0 then + bchar = b + end + else + if c < 128 then + -- whatever + elseif 256 * (c - 128) + d >= nk then + return someerror("invalid ligature table") + end + if (a < 128) and (i - 0 + a + 1 >= nl) then + return someerror("invalid ligature table") + end + end + if a == 255 then + blabel = 256 * c + d + end + end + end + local allkerns = { } + for i=0,nk-1 do + allkerns[i] = readscaled() + end + local extensibles = { } + for i=0,ne-1 do + extensibles[i] = wide and { + top = readcardinal2(s), + bot = readcardinal2(s), + mid = readcardinal2(s), + rep = readcardinal2(s), + } or { + top = readcardinal1(s), + bot = readcardinal1(s), + mid = readcardinal1(s), + rep = readcardinal1(s), + } + end + for i=1,np do + if i == 1 then + parameters[i] = readunscaled() + else + parameters[i] = readscaled() + end + end + for i=1,7 do + if not parameters[i] then + parameters[i] = 0 + end + end + -- + setposition(s,saved) + local extras = false + if blabel ~= nl then + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + -- if l.op >= 128 then + -- extras = true -- kern + -- else + extras = true -- ligature + -- end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + end + if extras then + local ligas = { } + local kerns = { } + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + kerns[nxt] = allkerns[256 * (op - 128) + rem] + else + ligas[nxt] = { type = op * 2 + 1, char = rem } + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break; + end + k = k + skip + 1 + end + end + if next(kerns) then + local glyph = glyphs[leftboundary] + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + local glyph = glyphs[leftboundary] + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + for i=bc,ec do + local glyph, width, height, depth, italic, tag, remainder + if wide then + width = readcardinal2(s) + height = readcardinal1(s) + depth = readcardinal1(s) + italic = readcardinal1(s) + tag = readcardinal1(s) + remainder = readcardinal2(s) + else + width = readcardinal1(s) + height = readcardinal1(s) + depth = extract(height,0,4) + height = extract(height,4,4) + italic = readcardinal1(s) + tag = extract(italic,0,2) + italic = extract(italic,2,6) + remainder = readcardinal1(s) + end + if width == 0 then + -- nothing + else + if width >= nw or height >= nh or depth >= nd or italic >= ni then + return someerror("invalid dimension index") + end + local extensible, nextinsize + if tag == 0 then + -- nothing special + else + local r = remainder + if tag == 1 then + if r >= nl then + return someerror("invalid ligature index") + end + elseif tag == 2 then + if r < bc or r > ec then + return someerror("invalid chain index") + end + while r < i do + local g = glyphs[r] + if g.tag ~= list_tag then + break + end + r = g.remainder + end + if r == i then + return someerror("cycles in chain") + end + nextinsize = r + elseif tag == 3 then + if r >= ne then + return someerror("bad extensible") + end + extensible = extensibles[r] -- remainder ? + remainder = 0 + end + end + glyphs[i] = { + width = widths [width], + height = heights[height], + depth = depths [depth], + italic = italics[italic], + tag = tag, + -- index = i, + remainder = remainder, + extensible = extensible, + next = nextinsize, + } + end + end + for i=bc,ec do + local glyph = glyphs[i] + if glyph.tag == 1 then + -- ligature + local k = glyph.remainder + local l = ligatures[k] + if l.skip > 128 then + k = 256 * l.op + l.rem + end + local ligas = { } + local kerns = { } + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + local kern = allkerns[256 * (op - 128) + rem] + if nxt == bchar then + kerns[rightboundary] = kern + end + kerns[nxt] = kern + else + local ligature = { type = op * 2 + 1, char = rem } + if nxt == bchar then + ligas[rightboundary] = ligature + end + ligas[nxt] = ligature -- shared + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + if next(kerns)then + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + end + -- + if bchar ~= boundarychar then + glyphs[rightboundary] = copy(glyphs[bchar]) + end + -- + -- for k, v in next, glyphs do + -- v.tag = nil + -- v.remainder = nil + -- end + -- + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + parameters = parameters, + designsize = designsize, + size = designsize, + direction = direction, + -- checksum = checksum, + -- embedding = "unknown", + -- extend = 1000, + -- slant = 0, + -- squeeze = 0, + -- format = "unknown", + -- identity = "unknown", + -- mode = 0, + -- streamprovider = 0, + -- tounicode = 0, + -- type = "unknown", + -- units_per_em = 0, + -- used = false, + -- width = 0, + -- writingmode = "unknown", + } + end + +end + +do + + local push = { "push" } + local push = { "pop" } + + local w, x, y, z, f + local stack + local s, result, r + local alpha, beta, z + + local function scaled1() + local a = readbytes(s,1) + if a == 0 then + return 0 + elseif a == 255 then + return - alpha + else + return 0 -- error + end + end + + local function scaled2() + local a, b = readbytes(s,2) + local sw = idiv(b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled3() + local a, b, c = readbytes(s,3) + local sw = idiv(rshift(c*z,8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled4() + local a, b, c, d = readbytes(s,4) + local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function dummy() + end + + local actions = { + + [128] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } p = p + 1 end, + [129] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } p = p + 2 end, + [130] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal3(s) } p = p + 3 end, + [131] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } p = p + 4 end, + + [132] = function() + r = r + 1 + result[r] = { "rule", scaled4(), scaled4() } + p = p + 8 + end, + + [133] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } + r = r + 1 result[r] = pop + p = p + 1 + end, + [134] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 2 + end, + [135] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 3 + end, + [136] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } + r = r + 1 result[r] = pop + p = p + 4 + end, + + [137] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "rule", scaled4(), scaled4() } + r = r + 1 result[r] = pop + p = p + 8 + end, + + [138] = dummy, -- nop + [139] = dummy, -- bop + [140] = dummy, -- eop + + [141] = function() + insert(stack, { w, x, y, z }) + r = r + 1 + result[r] = push + end, + [142] = function() + local t = remove(stack) + if t then + w, x, y, z = t[1], t[2], t[3], t[4] + r = r + 1 + result[r] = pop + end + end, + + [143] = function() r = r + 1 result[r] = { "right", scaled1() } p = p + 1 end, + [144] = function() r = r + 1 result[r] = { "right", scaled2() } p = p + 2 end, + [145] = function() r = r + 1 result[r] = { "right", scaled3() } p = p + 3 end, + [146] = function() r = r + 1 result[r] = { "right", scaled4() } p = p + 4 end, + + [148] = function() w = scaled1() r = r + 1 result[r] = { "right", w } p = p + 1 end, + [149] = function() w = scaled2() r = r + 1 result[r] = { "right", w } p = p + 2 end, + [150] = function() w = scaled3() r = r + 1 result[r] = { "right", w } p = p + 3 end, + [151] = function() w = scaled4() r = r + 1 result[r] = { "right", w } p = p + 4 end, + + [153] = function() x = scaled1() r = r + 1 result[r] = { "right", x } p = p + 1 end, + [154] = function() x = scaled2() r = r + 1 result[r] = { "right", x } p = p + 2 end, + [155] = function() x = scaled3() r = r + 1 result[r] = { "right", x } p = p + 3 end, + [156] = function() x = scaled4() r = r + 1 result[r] = { "right", x } p = p + 4 end, + + [157] = function() r = r + 1 result[r] = { "down", scaled1() } p = p + 1 end, + [158] = function() r = r + 1 result[r] = { "down", scaled2() } p = p + 2 end, + [159] = function() r = r + 1 result[r] = { "down", scaled3() } p = p + 3 end, + [160] = function() r = r + 1 result[r] = { "down", scaled4() } p = p + 4 end, + + [162] = function() y = scaled1() r = r + 1 result[r] = { "down", y } p = p + 1 end, + [163] = function() y = scaled2() r = r + 1 result[r] = { "down", y } p = p + 2 end, + [164] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 3 end, + [165] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 4 end, + + [167] = function() z = scaled1() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [168] = function() z = scaled2() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [169] = function() z = scaled3() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [170] = function() z = scaled4() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + + [147] = function() r = r + 1 result[r] = { "right", w } end, + [152] = function() r = r + 1 result[r] = { "right", x } end, + [161] = function() r = r + 1 result[r] = { "down", y } end, + [166] = function() r = r + 1 result[r] = { "down", z } end, + + [235] = function() f = readcardinal1(s) p = p + 1 end, + [236] = function() f = readcardinal2(s) p = p + 3 end, + [237] = function() f = readcardinal3(s) p = p + 3 end, + [238] = function() f = readcardinal4(s) p = p + 4 end, + + [239] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 1 + n end, + [240] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 2 + n end, + [241] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 3 + n end, + [242] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 4 + n end, + + [250] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 1 + n end, + [251] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 2 + n end, + [252] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 3 + n end, + [253] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 4 + n end, + + } + + table.setmetatableindex(actions,function(t,cmd) + local v + if cmd >= 0 and cmd <= 127 then + v = function() + if f == 0 then + f = 1 + end + r = r + 1 ; result[r] = { "slot", f, cmd } + end + elseif cmd >= 171 and cmd <= 234 then + cmd = cmd - 170 + v = function() + r = r + 1 ; result[r] = { "font", cmd } + end + else + v = dummy + end + t[cmd] = v + return v + end) + + function readers.loadvf(filename,data) + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + s = openstream(filename) + if not s then + return someerror() + end + -- + local cmd = readcardinal1(s) + if cmd ~= 247 then + return someerror("bad preamble") + end + cmd = readcardinal1(s) + if cmd ~= 202 then + return someerror("bad version") + end + local header = readstring(s,readcardinal1(s)) + local checksum = readcardinal4(s) + local designsize = idiv(readcardinal4(s),16) + local fonts = data and data.fonts or { } + local glyphs = data and data.glyphs or { } + -- + alpha = 16 + z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + beta = idiv(256,alpha) + alpha = alpha * z + -- + cmd = readcardinal1(s) + while true do + local n + if cmd == 243 then + n = readcardinal1(s) + 1 + elseif cmd == 244 then + n = readcardinal2(s) + 1 + elseif cmd == 245 then + n = readcardinal3(s) + 1 + elseif cmd == 246 then + n = readcardinal4(s) + 1 + else + break + end + local checksum = skipbytes(s,4) + local size = scaled4() + local designsize = idiv(readcardinal4(s),16) + local pathlen = readcardinal1(s) + local namelen = readcardinal1(s) + local path = readstring(s,pathlen) + local name = readstring(s,namelen) + fonts[n] = { path = path, name = name, size = size } + cmd = readcardinal1(s) + end + local index = 0 + while cmd and cmd <= 242 do + local width = 0 + local length = 0 + local checksum = 0 + if cmd == 242 then + length = readcardinal4(s) + checksum = readcardinal4(s) + width = readcardinal4(s) + else + length = cmd + checksum = readcardinal1(s) + width = readcardinal3(s) + end + w, x, y, z, f = 0, 0, 0, 0, false + stack, result, r, p = { }, { }, 0, 0 + while p < length do + local cmd = readcardinal1(s) + p = p + 1 + actions[cmd]() + end + local glyph = glyphs[index] + if glyph then + glyph.width = width + glyph.commands = result + else + glyphs[index] = { + width = width, + commands = result, + } + end + index = index + 1 + if #stack > 0 then + -- error: more pushes than pops + end + if packet_length ~= 0 then + -- error: invalid packet length + end + cmd = readcardinal1(s) + end + if readcardinal1(s) ~= 248 then + -- error: no post + end + s, result, r = nil, nil, nil + if data then + data.glyphs = data.glyphs or glyphs + data.fonts = data.fonts or fonts + return data + else + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + designsize = designsize, + header = header, + fonts = fonts, + } + end + end + + -- the replacement loader (not sparse): + + function readers.loadtfmvf(tfmname,size) + local vfname = file.addsuffix(file.nameonly(tfmfile),"vf") + local tfmfile = tfmname + local vffile = resolvers.findbinfile(vfname,"ovf") + if tfmfile and tfmfile ~= "" then + if size < 0 then + size = idiv(65536 * -size,100) + end + local data = readers.loadtfm(tfmfile) + if data.error then + return data + end + if vffile and vffile ~= "" then + data = readers.loadvf(vffile,data) + if data.error then + return data + end + end + local designsize = data.designsize + local glyphs = data.glyphs + local parameters = data.parameters + local fonts = data.fonts + if size ~= designsize then + local factor = size / designsize + for index, glyph in next, glyphs do + if next(glyph) then + glyph.width = round(factor*glyph.width) + glyph.height = round(factor*glyph.height) + glyph.depth = round(factor*glyph.depth) + local italic = glyph.italic + if italic == 0 then + glyph.italic = nil + else + glyph.italic = round(factor*glyph.italic) + end + -- + local kerns = glyph.kerns + if kerns then + for index, kern in next, kerns do + kerns[index] = round(factor*kern) + end + end + -- + local commands = glyph.commands + if commands then + for i=1,#commands do + local c = commands[i] + local t = c[1] + if t == "down" or t == "right" then + c[2] = round(factor*c[2]) + elseif t == "rule" then + c[2] = round(factor*c[2]) + c[3] = round(factor*c[3]) + end + end + end + else + glyphs[index] = nil + end + end + for i=2,30 do + local p = parameters[i] + if p then + parameters[i] = round(factor*p) + else + break + end + end + if fonts then + for k, v in next, fonts do + v.size = round(factor*v.size) + end + end + else + for index, glyph in next, glyphs do + if next(glyph) then + if glyph.italic == 0 then + glyph.italic = nil + end + else + glyphs[index] = nil + end + end + end + -- + parameters.slant = parameters[1] + parameters.space = parameters[2] + parameters.spacestretch = parameters[3] + parameters.spaceshrink = parameters[4] + parameters.xheight = parameters[5] + parameters.quad = parameters[6] + parameters.extraspace = parameters[7] + -- + for i=1,7 do + parameters[i] = nil -- so no danger for async + end + -- + data.characters = glyphs + data.glyphs = nil + data.size = size + -- we assume type1 for now ... maybe the format should be unknown + data.filename = tfmfile -- file.replacesuffix(tfmfile,"pfb") + data.format = "unknown" + -- + return data + end + end + +end + +-- inspect(readers.loadtfmvf(resolvers.findfile("mi-iwonari.tfm"))) +-- inspect(readers.loadtfm(resolvers.findfile("texnansi-palatinonova-regular.tfm"))) +-- inspect(readers.loadtfm(resolvers.findfile("cmex10.tfm"))) +-- inspect(readers.loadtfm(resolvers.findfile("cmr10.tfm"))) +-- local t = readers.loadtfmvf("texnansi-lte50019.tfm") +-- inspect(t) diff --git a/tex/context/base/mkxl/lang-dis.lmt b/tex/context/base/mkxl/lang-dis.lmt index 5c4ab1e34..36fea59c0 100644 --- a/tex/context/base/mkxl/lang-dis.lmt +++ b/tex/context/base/mkxl/lang-dis.lmt @@ -205,7 +205,7 @@ local flatten = languages.flatten nodes.handlers.flattenline = flatten function nodes.handlers.flatten(head,where) - if head and (where == "box" or where == "adjusted_hbox") then + if head and (where == "box" or where == "adjustedhbox") then return flatten(head) end return head diff --git a/tex/context/base/mkxl/lang-hyp.lmt b/tex/context/base/mkxl/lang-hyp.lmt index 590528495..90823851e 100644 --- a/tex/context/base/mkxl/lang-hyp.lmt +++ b/tex/context/base/mkxl/lang-hyp.lmt @@ -1645,7 +1645,7 @@ featureset.hyphenonly = hyphenonly == v_yes function hyphenators.handler(head,groupcode) if usedmethod then - if optimize and (groupcode == "hbox" or groupcode == "adjusted_hbox") then + if optimize and (groupcode == "hbox" or groupcode == "adjustedhbox") then if getcount("hyphenstate") > 0 then forced = false return usedmethod(head) diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt index 6183d073a..0ac497d57 100644 --- a/tex/context/base/mkxl/math-act.lmt +++ b/tex/context/base/mkxl/math-act.lmt @@ -110,7 +110,7 @@ end function mathematics.checkaccentbaseheight(target,original) local mathparameters = target.mathparameters if mathparameters and mathparameters.AccentBaseHeight == 0 then - mathparameters.AccentBaseHeight = target.parameters.x_height -- needs checking + mathparameters.AccentBaseHeight = target.parameters.xheight -- needs checking end end @@ -565,11 +565,11 @@ end -- local function fix(target,original,targetcharacters,unicode,factor) -- local chardata = targetcharacters[unicode] -- if chardata and factor then --- local accent = chardata.top_accent +-- local accent = chardata.topaccent -- if not accent then -- local width = chardata.width or 0 -- local accent = (tonumber(factor) and factor * width) or (factor and minint) --- chardata.top_accent = accent +-- chardata.topaccent = accent -- if trace_tweaking then -- report_tweak("fixing accent %U",target,original,unicode) -- end @@ -715,15 +715,15 @@ local function extensiblecode(font,unicode) if not char then return unknown end - if character.horiz_variants then - if character.vert_variants then + if character.hvariants then + if character.vvariants then return { e_mixed, code, character } else local m = char.mathextensible local e = m and extensibles[m] return e and { e, code, character } or unknown end - elseif character.vert_variants then + elseif character.vvariants then local m = char.mathextensible local e = m and extensibles[m] return e and { e, code, character } or unknown @@ -765,19 +765,19 @@ local function horizontalcode(family,unicode) local loffset = 0 local roffset = 0 if kind == e_left then - local charlist = data[3].horiz_variants + local charlist = data[3].hvariants if charlist then local left = charlist[1] loffset = abs((left["start"] or 0) - (left["end"] or 0)) end elseif kind == e_right then - local charlist = data[3].horiz_variants + local charlist = data[3].hvariants if charlist then local right = charlist[#charlist] roffset = abs((right["start"] or 0) - (right["end"] or 0)) end elseif kind == e_horizontal then - local charlist = data[3].horiz_variants + local charlist = data[3].hvariants if charlist then local left = charlist[1] local right = charlist[#charlist] diff --git a/tex/context/base/mkxl/math-dim.lmt b/tex/context/base/mkxl/math-dim.lmt new file mode 100644 index 000000000..1bf2420bf --- /dev/null +++ b/tex/context/base/mkxl/math-dim.lmt @@ -0,0 +1,249 @@ +if not modules then modules = { } end modules ['math-dim'] = { + version = 1.001, + comment = "companion to math-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The radical_rule value is also used as a trigger. In luatex the accent +-- placement happens either the opentype way (using topaccent cum suis) or the +-- traditional way. In order to determine what method to use the \Umathradicalrule +-- setting is consulted to determine what method to use. This is more efficient +-- than analyzing the (potentially spread over multiple families) situation. For +-- this reason we need to set the radical_rule here. It used to be "<unset>" in +-- which case the engine takes the rulethickness. In c-speak: +-- +-- int compat_mode = (radical_rule(cur_style) == undefined_math_parameter) ; +-- +-- In the meantime things have been updated and we now have two code paths. + +local abs, next = math.abs, next + +local defaults = { + axis = { default = { "AxisHeight", "axisheight" }, }, + accent_base_height = { default = { "AccentBaseHeight", "xheight" }, }, + fraction_del_size = { default = { "FractionDelimiterSize", "delim2" }, + cramped_display_style = { "FractionDelimiterDisplayStyleSize", "delim1" }, + display_style = { "FractionDelimiterDisplayStyleSize", "delim1" }, }, + fraction_denom_down = { default = { "FractionDenominatorShiftDown", "denom2" }, + cramped_display_style = { "FractionDenominatorDisplayStyleShiftDown", "denom1" }, + display_style = { "FractionDenominatorDisplayStyleShiftDown", "denom1" }, }, + fraction_denom_vgap = { default = { "FractionDenominatorGapMin", "defaultrulethickness" }, + cramped_display_style = { "FractionDenominatorDisplayStyleGapMin", "3*defaultrulethickness" }, + display_style = { "FractionDenominatorDisplayStyleGapMin", "3*defaultrulethickness" }, }, + fraction_num_up = { default = { "FractionNumeratorShiftUp", "num2" }, + cramped_display_style = { "FractionNumeratorDisplayStyleShiftUp", "num1" }, + display_style = { "FractionNumeratorDisplayStyleShiftUp", "num1" }, }, + fraction_num_vgap = { default = { "FractionNumeratorGapMin", "defaultrulethickness" }, + cramped_display_style = { "FractionNumeratorDisplayStyleGapMin", "3*defaultrulethickness" }, + display_style = { "FractionNumeratorDisplayStyleGapMin", "3*defaultrulethickness" }, }, + skewed_fraction_hgap = { default = { "SkewedFractionHorizontalGap", "mathquad/2" }, + cramped_display_style = { "SkewedFractionHorizontalGap", "mathquad/2" }, + display_style = { "SkewedFractionHorizontalGap", "mathquad/2" }, }, + skewed_fraction_vgap = { default = { "SkewedFractionVerticalGap", "xheight" }, + cramped_display_style = { "SkewedFractionVerticalGap", "xheight" }, + display_style = { "SkewedFractionVerticalGap", "xheight" }, }, + fraction_rule = { default = { "FractionRuleThickness", "defaultrulethickness" }, }, + limit_above_bgap = { default = { "UpperLimitBaselineRiseMin", "bigopspacing3" }, }, + limit_above_vgap = { default = { "UpperLimitGapMin", "bigopspacing1" }, }, + limit_above_kern = { default = { "0", "bigopspacing5" }, }, + limit_below_bgap = { default = { "LowerLimitBaselineDropMin", "bigopspacing4" }, }, + limit_below_vgap = { default = { "LowerLimitGapMin", "bigopspacing2" }, }, + limit_below_kern = { default = { "0", "bigopspacing5" }, }, + math_operator_size = { default = { "DisplayOperatorMinHeight", "mathxheight*3" }, }, -- 2 + overbar_kern = { default = { "OverbarExtraAscender", "defaultrulethickness" }, }, + overbar_rule = { default = { "OverbarRuleThickness", "defaultrulethickness" }, }, + overbar_vgap = { default = { "OverbarVerticalGap", "3*defaultrulethickness" }, }, + quad = { default = { "fontsize(f)", "mathquad" }, }, + radical_kern = { default = { "RadicalExtraAscender", "defaultrulethickness" }, }, + radical_rule = { default = { "RadicalRuleThickness", "defaultrulethickness" }, }, + -- default = { "surdheight(f)", "defaultrulethickness" }, + radical_vgap = { default = { "RadicalVerticalGap", "defaultrulethickness+(abs(defaultrulethickness)/4)" }, + display_style = { "RadicalDisplayStyleVerticalGap", "defaultrulethickness+(abs(mathxheight)/4)" }, }, + space_after_script = { default = { "SpaceAfterScript", "scriptspace" }, }, + space_before_script = { default = { "SpaceAfterScript", "scriptspace" }, }, + stack_denom_down = { default = { "StackBottomShiftDown", "denom2" }, + cramped_display_style = { "StackBottomDisplayStyleShiftDown", "denom1" }, + display_style = { "StackBottomDisplayStyleShiftDown", "denom1" }, }, + stack_num_up = { default = { "StackTopShiftUp", "num3" }, + cramped_display_style = { "StackTopDisplayStyleShiftUp", "num1" }, + display_style = { "StackTopDisplayStyleShiftUp", "num1" }, }, + stack_vgap = { default = { "StackGapMin", "3*defaultrulethickness" }, + cramped_display_style = { "StackDisplayStyleGapMin", "7*defaultrulethickness" }, + display_style = { "StackDisplayStyleGapMin", "7*defaultrulethickness" }, }, + sub_shift_down = { default = { "SubscriptShiftDown", "sub1" }, }, + sub_shift_drop = { default = { "SubscriptBaselineDropMin", "subdrop" }, }, + sub_sup_shift_down = { default = { "SubscriptShiftDown", "sub2" }, }, + sub_top_max = { default = { "SubscriptTopMax", "abs(mathxheight*4)/5" }, }, + subsup_vgap = { default = { "SubSuperscriptGapMin", "4*defaultrulethickness" }, }, + sup_bottom_min = { default = { "SuperscriptBottomMin", "abs(mathxheight)/4" }, }, + sup_shift_drop = { default = { "SuperscriptBaselineDropMax", "supdrop" }, }, + sup_shift_up = { cramped_display_style = { "SuperscriptShiftUpCramped", "sup3" }, + cramped_script_script_style = { "SuperscriptShiftUpCramped", "sup3" }, + cramped_script_style = { "SuperscriptShiftUpCramped", "sup3" }, + cramped_text_style = { "SuperscriptShiftUpCramped", "sup3" }, + display_style = { "SuperscriptShiftUp", "sup1" }, + script_script_style = { "SuperscriptShiftUp", "sup2" }, + script_style = { "SuperscriptShiftUp", "sup2" }, + text_style = { "SuperscriptShiftUp", "sup2" }, }, + sup_sub_bottom_max = { default = { "SuperscriptBottomMaxWithSubscript", "abs(mathxheight*4)/5" }, }, + underbar_kern = { default = { "UnderbarExtraDescender", "0" }, }, + underbar_rule = { default = { "UnderbarRuleThickness", "defaultrulethickness" }, }, + underbar_vgap = { default = { "UnderbarVerticalGap", "3*defaultrulethickness" }, }, + connector_overlap_min = { default = { "MinConnectorOverlap", "0.25*defaultrulethickness" }, }, + over_delimiter_vgap = { default = { "StretchStackGapBelowMin", "bigopspacing1" }, }, + over_delimiter_bgap = { default = { "StretchStackTopShiftUp", "bigopspacing3" }, }, + under_delimiter_vgap = { default = { "StretchStackGapAboveMin", "bigopspacing2" }, }, + under_delimiter_bgap = { default = { "StretchStackBottomShiftDown", "bigopspacing4" }, }, + radical_degree_before = { default = { "RadicalKernBeforeDegree", "(5/18)*quad" }, }, + radical_degree_after = { default = { "RadicalKernAfterDegree", "(-10/18)*quad" }, }, + radical_degree_raise = { default = { "RadicalDegreeBottomRaisePercent", "60" }, }, + no_limit_sub_factor = { default = { "NoLimitSubFactor", "0" }, }, + no_limit_sup_factor = { default = { "NoLimitSupFactor", "0" }, }, +} + +local styles = { + 'cramped_display_style', + 'cramped_script_script_style', + 'cramped_script_style', + 'cramped_text_style', + 'display_style', + 'script_script_style', + 'script_style', + 'text_style', +} + +for k, v in next, defaults do + for _, s in next, styles do + if not v[s] then + v[s] = v.default + end + end +end + +-- we cannot use a metatable because we do a copy (takes a bit more work) +-- +-- local mt = { } setmetatable(defaults,mt) +-- +-- mt.__index = function(t,s) +-- return t.default or t.text_style or 0 +-- end + +function mathematics.dimensions(dimens) -- beware, dimens get spoiled + if dimens.SpaceAfterScript then + dimens.SubscriptShiftDownWithSuperscript = dimens.SubscriptShiftDown * 1.5 -- move this one + return table.fastcopy(dimens), { } + elseif dimens.AxisHeight or dimens.axisheight then + local t = { } + local mathxheight = dimens.xheight or 10*65536 + local mathquad = dimens.quad or 10*65536 + local defaultrulethickness = dimens.FractionDenominatorGapMin or dimens.defaultrulethickness or 0.4*65536 + dimens["0"] = 0 + dimens["60"] = 60 + dimens["0.25*defaultrulethickness"] = defaultrulethickness / 4 + dimens["3*defaultrulethickness"] = 3 * defaultrulethickness + dimens["4*defaultrulethickness"] = 4 * defaultrulethickness + dimens["7*defaultrulethickness"] = 7 * defaultrulethickness + dimens["(5/18)*quad"] = (mathquad * 5) / 18 + dimens["(-10/18)*quad"] = - (mathquad * 10) / 18 + dimens["mathxheight*3"] = mathxheight * 3 -- needs checking + dimens["abs(mathxheight*4)/5"] = abs(mathxheight * 4) / 5 + dimens["defaultrulethickness+(abs(defaultrulethickness)/4)"] = defaultrulethickness+(abs(defaultrulethickness) / 4) + dimens["defaultrulethickness+(abs(mathxheight)/4)"] = defaultrulethickness+(abs(mathxheight) / 4) + dimens["abs(mathxheight)/4"] = abs(mathxheight) / 4 + dimens["abs(mathxheight*4)/5"] = abs(mathxheight * 4) / 5 + dimens["<not set>"] = false + dimens["script_space"] = false -- at macro level + for variable, styles in next, defaults do + local tt = { } + for style, default in next, styles do + local one = default[1] + local two = default[2] + local value = dimens[one] + if value then + tt[style] = value + else + value = dimens[two] + if value == false then + tt[style] = nil + else + tt[style] = value or 0 + end + end + end + t[variable] = tt + end + local d = { + AccentBaseHeight = t . accent_base_height . text_style, + AxisHeight = t . axis . text_style, + -- DelimitedSubFormulaMinHeight + DisplayOperatorMinHeight = t . math_operator_size . text_style, -- no longer let tex decide (weird values) + -- FlattenedAccentBaseHeight + FractionDenominatorDisplayStyleGapMin = t . fraction_denom_vgap . display_style, + FractionDenominatorDisplayStyleShiftDown = t . fraction_denom_down . display_style, + FractionDenominatorGapMin = t . fraction_denom_vgap . text_style, + FractionDenominatorShiftDown = t . fraction_denom_down . text_style, + FractionNumeratorDisplayStyleGapMin = t . fraction_num_vgap . display_style, + FractionNumeratorDisplayStyleShiftUp = t . fraction_num_up . display_style, + FractionNumeratorGapMin = t . fraction_num_vgap . text_style, + FractionNumeratorShiftUp = t . fraction_num_up . text_style, + FractionRuleThickness = t . fraction_rule . text_style, + FractionDelimiterSize = t . fraction_del_size . text_style, + FractionDelimiterDisplayStyleSize = t . fraction_del_size . display_style, + LowerLimitBaselineDropMin = t . limit_below_bgap . text_style, + LowerLimitGapMin = t . limit_below_vgap . text_style, + -- MathLeading + MinConnectorOverlap = t . connector_overlap_min . text_style, + OverbarExtraAscender = t . overbar_kern . text_style, + OverbarRuleThickness = t . overbar_rule . text_style, + OverbarVerticalGap = t . overbar_vgap . text_style, + RadicalDisplayStyleVerticalGap = t . radical_vgap . display_style, + RadicalExtraAscender = t . radical_kern . text_style, + RadicalRuleThickness = t . radical_rule . text_style, + RadicalVerticalGap = t . radical_vgap . text_style, + RadicalKernBeforeDegree = t . radical_degree_before . display_style, + RadicalKernAfterDegree = t . radical_degree_after . display_style, + RadicalDegreeBottomRaisePercent = t . radical_degree_raise . display_style, + -- ScriptPercentScaleDown + -- ScriptScriptPercentScaleDown + -- SkewedFractionHorizontalGap + -- SkewedFractionVerticalGap + SpaceAfterScript = t . space_after_script . text_style, + StackBottomDisplayStyleShiftDown = t . stack_denom_down . display_style, + StackBottomShiftDown = t . stack_denom_down . text_style, + StackDisplayStyleGapMin = t . stack_vgap . display_style, + StackGapMin = t . stack_vgap . text_style, + StackTopDisplayStyleShiftUp = t . stack_num_up . display_style, + StackTopShiftUp = t . stack_num_up . text_style, + StretchStackGapBelowMin = t . over_delimiter_vgap . text_style, + StretchStackTopShiftUp = t . over_delimiter_bgap . text_style, + StretchStackGapAboveMin = t . under_delimiter_vgap . text_style, + StretchStackBottomShiftDown = t . under_delimiter_bgap . text_style, + SubSuperscriptGapMin = t . subsup_vgap . text_style, + SubscriptBaselineDropMin = t . sub_shift_drop . text_style, + SubscriptShiftDown = t . sub_shift_down . text_style, + SubscriptShiftDownWithSuperscript = t . sub_sup_shift_down . text_style, + SubscriptTopMax = t . sub_top_max . text_style, + SuperscriptBaselineDropMax = t . sup_shift_drop . text_style, + SuperscriptBottomMaxWithSubscript = t . sup_sub_bottom_max . text_style, + SuperscriptBottomMin = t . sup_bottom_min . text_style, + SuperscriptShiftUp = t . sup_shift_up . text_style, + SuperscriptShiftUpCramped = t . sup_shift_up . cramped_text_style, + UnderbarExtraDescender = t . underbar_kern . text_style, + UnderbarRuleThickness = t . underbar_rule . text_style, + UnderbarVerticalGap = t . underbar_vgap . text_style, + UpperLimitBaselineRiseMin = t . limit_above_bgap . text_style, + UpperLimitGapMin = t . limit_above_vgap . text_style, + } + + -- too fragile for tx/px ... even the same values give different results + d.DisplayOperatorMinHeight = nil + -- + d.AccentBaseHeight = 0 -- here? still? + return d, t -- t only for diagnostics + else + return { }, { } + end +end + diff --git a/tex/context/base/mkxl/math-fbk.lmt b/tex/context/base/mkxl/math-fbk.lmt index 32ad909f7..80b99d83b 100644 --- a/tex/context/base/mkxl/math-fbk.lmt +++ b/tex/context/base/mkxl/math-fbk.lmt @@ -297,10 +297,10 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s break end end - local hv = olddata.horiz_variants + local hv = olddata.hvariants if hv then hv = fastcopy(hv) - newdata.horiz_variants = hv + newdata.hvariants = hv for i=1,#hv do local hvi = hv[i] local oldglyph = hvi.glyph @@ -314,7 +314,7 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s } hvi.glyph = addprivate(target,formatters["M-H-%H"](oldglyph),newdata) else - report_fallbacks("error in fallback: no valid horiz_variants, slot %X, index %i",oldglyph,i) + report_fallbacks("error in fallback: no valid hvariants, slot %X, index %i",oldglyph,i) end end end @@ -393,7 +393,7 @@ local function smashed(data,unicode,private) local height = target.parameters.xheight / 2 local c, done = accent_to_extensible(target,private,data.original,unicode,height,0,nil,-height,unicode) if done then - c.top_accent = nil -- or maybe also all the others + c.topaccent = nil -- or maybe also all the others end return c end @@ -717,7 +717,7 @@ virtualcharacters[0x305] = function(data) height = height, depth = depth, commands = { { "rule", height, width } }, - horiz_variants = { + hvariants = { { advance = width, ["end"] = used, diff --git a/tex/context/base/mkxl/math-ini.lmt b/tex/context/base/mkxl/math-ini.lmt index d199d5063..4ac76fa62 100644 --- a/tex/context/base/mkxl/math-ini.lmt +++ b/tex/context/base/mkxl/math-ini.lmt @@ -601,7 +601,7 @@ function mathematics.big(tfmdata,unicode,n,method) local t = tfmdata.characters local c = t[unicode] if c and n > 0 then - local vv = c.vert_variants or c.next and t[c.next].vert_variants + local vv = c.vvariants or c.next and t[c.next].vvariants if vv then local vvn = vv[n] return vvn and vvn.glyph or vv[#vv].glyph or unicode diff --git a/tex/context/base/mkxl/math-ini.mkxl b/tex/context/base/mkxl/math-ini.mkxl index 3404e25f3..8ff839107 100644 --- a/tex/context/base/mkxl/math-ini.mkxl +++ b/tex/context/base/mkxl/math-ini.mkxl @@ -65,7 +65,7 @@ % test $[[\char948 \cldcontext{utf.char(948)}]]$ \registerctxluafile{math-ini}{autosuffix} -\registerctxluafile{math-dim}{} +\registerctxluafile{math-dim}{autosuffix} \registerctxluafile{math-act}{autosuffix} \registerctxluafile{math-ext}{} \registerctxluafile{math-vfu}{autosuffix} diff --git a/tex/context/base/mkxl/math-noa.lmt b/tex/context/base/mkxl/math-noa.lmt index 025333699..66e8caade 100644 --- a/tex/context/base/mkxl/math-noa.lmt +++ b/tex/context/base/mkxl/math-noa.lmt @@ -197,19 +197,19 @@ local undernoad_code = noadcodes.under local overnoad_code = noadcodes.over local vcenternoad_code = noadcodes.vcenter -local noad_code = nodecodes.noad -- attr nucleus sub sup -local accent_code = nodecodes.accent -- attr nucleus sub sup accent -local radical_code = nodecodes.radical -- attr nucleus sub sup left degree -local fraction_code = nodecodes.fraction -- attr nucleus sub sup left right -local subbox_code = nodecodes.subbox -- attr list -local submlist_code = nodecodes.submlist -- attr list -local mathchar_code = nodecodes.mathchar -- attr fam char -local mathtextchar_code = nodecodes.mathtextchar -- attr fam char -local delimiter_code = nodecodes.delimiter -- attr small_fam small_char large_fam large_char ------ style_code = nodecodes.style -- attr style ------ parameter_code = nodecodes.parameter -- attr style -local math_choice = nodecodes.choice -- attr display text script scriptscript -local fence_code = nodecodes.fence -- attr subtype +local noad_code = nodecodes.noad +local accent_code = nodecodes.accent +local radical_code = nodecodes.radical +local fraction_code = nodecodes.fraction +local subbox_code = nodecodes.subbox +local submlist_code = nodecodes.submlist +local mathchar_code = nodecodes.mathchar +local mathtextchar_code = nodecodes.mathtextchar +local delimiter_code = nodecodes.delimiter +----- style_code = nodecodes.style +----- parameter_code = nodecodes.parameter +local math_choice = nodecodes.choice +local fence_code = nodecodes.fence local leftfence_code = fencecodes.left local middlefence_code = fencecodes.middle @@ -316,8 +316,8 @@ local function process(start,what,n,parent) noad = getsuppre (start) if noad then process(noad,what,n,start) end -- list noad = getsubpre (start) if noad then process(noad,what,n,start) end -- list end - noad = getfield(start,"accent") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list + noad = getfield(start,"topaccent") if noad then process(noad,what,n,start) end -- list + noad = getfield(start,"botaccent") if noad then process(noad,what,n,start) end -- list -- elseif id == style_code then -- -- has a next -- elseif id == parameter_code then @@ -375,8 +375,8 @@ local function processnested(current,what,n) noad = getsuppre (current) if noad then process(noad,what,n,current) end -- list noad = getsubpre (current) if noad then process(noad,what,n,current) end -- list end - noad = getfield(current,"accent") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"bot_accent") if noad then process(noad,what,n,current) end -- list + noad = getfield(current,"topaccent") if noad then process(noad,what,n,current) end -- list + noad = getfield(current,"botaccent") if noad then process(noad,what,n,current) end -- list end end @@ -423,8 +423,8 @@ local function processstep(current,process,n,id) noad = getsuppre (current) if noad then process(noad,n,current) end -- list noad = getsubpre (current) if noad then process(noad,n,current) end -- list end - noad = getfield(current,"accent") if noad then process(noad,n,current) end -- list - noad = getfield(current,"bot_accent") if noad then process(noad,n,current) end -- list + noad = getfield(current,"topaccent") if noad then process(noad,n,current) end -- list + noad = getfield(current,"botaccent") if noad then process(noad,n,current) end -- list end end @@ -584,7 +584,7 @@ do end end families[delimiter_code] = function(pointer) - if getfield(pointer,"small_fam") == 0 then + if getfield(pointer,"smallfamily") == 0 then local a = getattr(pointer,a_mathfamily) if a and a > 0 then setattr(pointer,a_mathfamily,0) @@ -593,23 +593,23 @@ do a = a - 3 end local fam = getfontoffamily(a) - local char = getfield(pointer,"small_char") + local char = getfield(pointer,"smallchar") local okay = fontcharacters[fam][char] if okay then - setfield(pointer,"small_fam",a) + setfield(pointer,"smallfamily",a) elseif a > 2 then - setfield(pointer,"small_fam",a-3) + setfield(pointer,"smallfamily",a-3) end - local char = getfield(pointer,"large_char") + local char = getfield(pointer,"largechar") local okay = fontcharacters[fam][char] if okay then - setfield(pointer,"large_fam",a) + setfield(pointer,"largefamily",a) elseif a > 2 then - setfield(pointer,"large_fam",a-3) + setfield(pointer,"largefamily",a-3) end else - setfield(pointer,"small_fam",0) - setfield(pointer,"large_fam",0) + setfield(pointer,"smallfamily",0) + setfield(pointer,"largefamily",0) end end end @@ -827,8 +827,8 @@ end -- empty and no larger next will be forced) -- -- beware: we don't use \delcode but \Udelcode and as such have --- no large_fam; also, we need to check for subtype and/or --- small_fam not being 0 because \. sits in 0,0 by default +-- no largefamily; also, we need to check for subtype and/or +-- smallfamily not being 0 because \. sits in 0,0 by default -- -- todo: just replace the character by an ord noad -- and remove the right delimiter as well diff --git a/tex/context/base/mkxl/math-tag.lmt b/tex/context/base/mkxl/math-tag.lmt index fa10c51c2..9ecc7047a 100644 --- a/tex/context/base/mkxl/math-tag.lmt +++ b/tex/context/base/mkxl/math-tag.lmt @@ -43,18 +43,18 @@ local nextnode = nuts.traversers.node local nodecodes = nodes.nodecodes -local noad_code = nodecodes.noad -- attr nucleus sub sup -local accent_code = nodecodes.accent -- attr nucleus sub sup accent -local radical_code = nodecodes.radical -- attr nucleus sub sup left degree -local fraction_code = nodecodes.fraction -- attr nucleus sub sup left right -local subbox_code = nodecodes.subbox -- attr list -local submlist_code = nodecodes.submlist -- attr list -local mathchar_code = nodecodes.mathchar -- attr fam char -local mathtextchar_code = nodecodes.mathtextchar -- attr fam char -local delimiter_code = nodecodes.delimiter -- attr small_fam small_char large_fam large_char -local style_code = nodecodes.style -- attr style -local choice_code = nodecodes.choice -- attr display text script scriptscript -local fence_code = nodecodes.fence -- attr subtype +local noad_code = nodecodes.noad +local accent_code = nodecodes.accent +local radical_code = nodecodes.radical +local fraction_code = nodecodes.fraction +local subbox_code = nodecodes.subbox +local submlist_code = nodecodes.submlist +local mathchar_code = nodecodes.mathchar +local mathtextchar_code = nodecodes.mathtextchar +local delimiter_code = nodecodes.delimiter +local style_code = nodecodes.style +local choice_code = nodecodes.choice +local fence_code = nodecodes.fence local accentcodes = nodes.accentcodes local fencecodes = nodes.fencecodes @@ -526,39 +526,39 @@ process = function(start) -- we cannot use the processor as we have no finalizer stop_tagged() end elseif id == accent_code then - local accent = getfield(start,"accent") - local bot_accent = getfield(start,"bot_accent") - if bot_accent then - if accent then + local topaccent = getfield(start,"topaccent") + local botaccent = getfield(start,"botaccent") + if botaccent then + if topaccent then setattr(start,a_tagged,start_tagged("munderover", { accent = true, - top = getunicode(accent), - bottom = getunicode(bot_accent), + top = getunicode(topaccent), + bottom = getunicode(botaccent), topfixed = subtype == fixedtopaccent_code or subtype == fixedbothaccent_code, bottomfixed = subtype == fixedbottomaccent_code or subtype == fixedbothaccent_code, })) processsubsup(start) - process(bot_accent) - process(accent) + process(botaccent) + process(topaccent) stop_tagged() else setattr(start,a_tagged,start_tagged("munder", { accent = true, - bottom = getunicode(bot_accent), + bottom = getunicode(botaccent), bottomfixed = subtype == fixedbottomaccent_code or subtype == fixedbothaccent_code, })) processsubsup(start) - process(bot_accent) + process(botaccent) stop_tagged() end - elseif accent then + elseif topaccent then setattr(start,a_tagged,start_tagged("mover", { accent = true, - top = getunicode(accent), + top = getunicode(topaccent), topfixed = subtype == fixedtopaccent_code or subtype == fixedbothaccent_code, })) processsubsup(start) - process(accent) + process(topaccent) stop_tagged() else processsubsup(start) diff --git a/tex/context/base/mkxl/math-vfu.lmt b/tex/context/base/mkxl/math-vfu.lmt index 6584b0158..abe336f53 100644 --- a/tex/context/base/mkxl/math-vfu.lmt +++ b/tex/context/base/mkxl/math-vfu.lmt @@ -9,7 +9,9 @@ if not modules then modules = { } end modules ['math-vfu'] = { -- All these math vectors .. thanks to Aditya and Mojca they become better and -- better. If you have problems with math fonts or miss characters report it to the -- ConTeXt mailing list. Also thanks to Boguslaw for finding a couple of errors. --- This mechanism will eventually disappear. + +-- This mechanism will eventually disappear or at least needs to be updated to the +-- way lmtx does virtual fonts. -- 20D6 -> 2190 -- 20D7 -> 2192 @@ -83,7 +85,7 @@ local shared = { } local function brace(main,characters,id,size,unicode,first,rule,left,right,rule,last) if not characters[unicode] then characters[unicode] = { - horiz_variants = { + hvariants = { { extender = 0, glyph = first }, { extender = 1, glyph = rule }, { extender = 0, glyph = left }, @@ -121,7 +123,7 @@ local function extension(main,characters,id,size,unicode,first,middle,last) if lw == 0 then lw = 1 end - chr.horiz_variants = { + chr.hvariants = { { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw }, { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = mw }, { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = lw }, @@ -131,7 +133,7 @@ end local function parent(main,characters,id,size,unicode,first,rule,last) if not characters[unicode] then characters[unicode] = { - horiz_variants = { + hvariants = { { extender = 0, glyph = first }, { extender = 1, glyph = rule }, { extender = 0, glyph = last }, @@ -150,7 +152,7 @@ local function make(main,characters,id,size,n,m) local dnslot = 0xFF200 + n local uprule = 0xFF300 + m local dnrule = 0xFF400 + m - local xu = main.parameters.x_height + 0.3*size + local xu = main.parameters.xheight + 0.3*size local xd = 0.3*size local w = c.width or 0 local h = c.height or 0 @@ -226,7 +228,7 @@ end local function raise(main,characters,id,size,unicode,private,n,id_of_smaller) -- this is a real fake mess local raised = fonts.hashes.characters[main.fonts[id_of_smaller].id][private] -- characters[private] if raised then - local up = 0.85 * main.parameters.x_height + local up = 0.85 * main.parameters.xheight local slot = { "slot", id_of_smaller, private } local commands = { push, upcommand[up], slot, @@ -659,10 +661,10 @@ local function copy_glyph(main,target,original,unicode,slot) break -- safeguard (when testing stuff) end end - local hv = olddata.horiz_variants + local hv = olddata.hvariants if hv then hv = fastcopy(hv) - newdata.horiz_variants = hv + newdata.hvariants = hv for i=1,#hv do local hvi = hv[i] local oldglyph = hvi.glyph @@ -677,10 +679,10 @@ local function copy_glyph(main,target,original,unicode,slot) hvi.glyph = addprivate(main,formatters["M-H-%H"](oldglyph),newdata) end end - local vv = olddata.vert_variants + local vv = olddata.vvariants if vv then vv = fastcopy(vv) - newdata.vert_variants = vv + newdata.vvariants = vv for i=1,#vv do local vvi = vv[i] local oldglyph = vvi.glyph @@ -822,8 +824,8 @@ function vfmath.define(specification,set,goodies) properties.fullname = fullname .. "-" .. unique end -- - if not parameters.x_height then - parameters.x_height = 0 + if not parameters.xheight then + parameters.xheight = 0 end -- local already_reported = false @@ -845,32 +847,33 @@ function vfmath.define(specification,set,goodies) elseif not newparameters then report_virtual("no parameters set in font %a",name) elseif ss.extension then - mathparameters.math_x_height = newparameters.x_height or 0 -- math_x_height : height of x - mathparameters.default_rule_thickness = newparameters[ 8] or 0 -- default_rule_thickness : thickness of \over bars - mathparameters.big_op_spacing1 = newparameters[ 9] or 0 -- big_op_spacing1 : minimum clearance above a displayed op - mathparameters.big_op_spacing2 = newparameters[10] or 0 -- big_op_spacing2 : minimum clearance below a displayed op - mathparameters.big_op_spacing3 = newparameters[11] or 0 -- big_op_spacing3 : minimum baselineskip above displayed op - mathparameters.big_op_spacing4 = newparameters[12] or 0 -- big_op_spacing4 : minimum baselineskip below displayed op - mathparameters.big_op_spacing5 = newparameters[13] or 0 -- big_op_spacing5 : padding above and below displayed limits + mathparameters.xheight = newparameters.xheight or 0 -- mathxheight : height of x + mathparameters.defaultrulethickness = newparameters[ 8] or 0 -- defaultrulethickness : thickness of \over bars + mathparameters.bigopspacing1 = newparameters[ 9] or 0 -- bigopspacing1 : minimum clearance above a displayed op + mathparameters.bigopspacing2 = newparameters[10] or 0 -- bigopspacing2 : minimum clearance below a displayed op + mathparameters.bigopspacing3 = newparameters[11] or 0 -- bigopspacing3 : minimum baselineskip above displayed op + mathparameters.bigopspacing4 = newparameters[12] or 0 -- bigopspacing4 : minimum baselineskip below displayed op + mathparameters.bigopspacing5 = newparameters[13] or 0 -- bigopspacing5 : padding above and below displayed limits -- report_virtual("loading and virtualizing font %a at size %p, setting ex parameters",name,size) elseif ss.parameters then - mathparameters.x_height = newparameters.x_height or mathparameters.x_height - mathparameters.x_height = mathparameters.x_height or fp.x_height or 0 -- x_height : height of x - mathparameters.num1 = newparameters[ 8] or 0 -- num1 : numerator shift-up in display styles - mathparameters.num2 = newparameters[ 9] or 0 -- num2 : numerator shift-up in non-display, non-\atop - mathparameters.num3 = newparameters[10] or 0 -- num3 : numerator shift-up in non-display \atop - mathparameters.denom1 = newparameters[11] or 0 -- denom1 : denominator shift-down in display styles - mathparameters.denom2 = newparameters[12] or 0 -- denom2 : denominator shift-down in non-display styles - mathparameters.sup1 = newparameters[13] or 0 -- sup1 : superscript shift-up in uncramped display style - mathparameters.sup2 = newparameters[14] or 0 -- sup2 : superscript shift-up in uncramped non-display - mathparameters.sup3 = newparameters[15] or 0 -- sup3 : superscript shift-up in cramped styles - mathparameters.sub1 = newparameters[16] or 0 -- sub1 : subscript shift-down if superscript is absent - mathparameters.sub2 = newparameters[17] or 0 -- sub2 : subscript shift-down if superscript is present - mathparameters.sup_drop = newparameters[18] or 0 -- sup_drop : superscript baseline below top of large box - mathparameters.sub_drop = newparameters[19] or 0 -- sub_drop : subscript baseline below bottom of large box - mathparameters.delim1 = newparameters[20] or 0 -- delim1 : size of \atopwithdelims delimiters in display styles - mathparameters.delim2 = newparameters[21] or 0 -- delim2 : size of \atopwithdelims delimiters in non-displays - mathparameters.axis_height = newparameters[22] or 0 -- axis_height : height of fraction lines above the baseline + mathparameters.xheight = newparameters.xheight + or mathparameters.xheight + or fs.xheight or 0 -- xheight : height of x + mathparameters.num1 = newparameters[ 8] or 0 -- num1 : numerator shift-up in display styles + mathparameters.num2 = newparameters[ 9] or 0 -- num2 : numerator shift-up in non-display, non-\atop + mathparameters.num3 = newparameters[10] or 0 -- num3 : numerator shift-up in non-display \atop + mathparameters.denom1 = newparameters[11] or 0 -- denom1 : denominator shift-down in display styles + mathparameters.denom2 = newparameters[12] or 0 -- denom2 : denominator shift-down in non-display styles + mathparameters.sup1 = newparameters[13] or 0 -- sup1 : superscript shift-up in uncramped display style + mathparameters.sup2 = newparameters[14] or 0 -- sup2 : superscript shift-up in uncramped non-display + mathparameters.sup3 = newparameters[15] or 0 -- sup3 : superscript shift-up in cramped styles + mathparameters.sub1 = newparameters[16] or 0 -- sub1 : subscript shift-down if superscript is absent + mathparameters.sub2 = newparameters[17] or 0 -- sub2 : subscript shift-down if superscript is present + mathparameters.sup_drop = newparameters[18] or 0 -- sup_drop : superscript baseline below top of large box + mathparameters.sub_drop = newparameters[19] or 0 -- sub_drop : subscript baseline below bottom of large box + mathparameters.delim1 = newparameters[20] or 0 -- delim1 : size of \atopwithdelims delimiters in display styles + mathparameters.delim2 = newparameters[21] or 0 -- delim2 : size of \atopwithdelims delimiters in non-displays + mathparameters.axisheight = newparameters[22] or 0 -- axisheight : height of fraction lines above the baseline -- report_virtual("loading and virtualizing font %a at size %p, setting sy parameters",name,size) end if ss.overlay then @@ -941,13 +944,13 @@ function vfmath.define(specification,set,goodies) local kerns = fci.kerns local width = fci.width local italic = fci.italic --- if trace_virtual then --- report_virtual("character %C uses index %H in vector %a for font %a, %s, %s", --- unicode,index,vectorname,fontname, --- kerns and "adding kerns" or "no kerns", --- kerns and "adding italic" or "no italic" --- ) --- end + -- if trace_virtual then + -- report_virtual("character %C uses index %H in vector %a for font %a, %s, %s", + -- unicode,index,vectorname,fontname, + -- kerns and "adding kerns" or "no kerns", + -- kerns and "adding italic" or "no italic" + -- ) + -- end if italic and italic > 0 then -- int_a^b if isextension then @@ -976,7 +979,7 @@ function vfmath.define(specification,set,goodies) if skewchar then local k = kerns[skewchar] if k then - t.top_accent = width/2 + k + t.topaccent = width/2 + k end end characters[unicode] = t @@ -1014,30 +1017,30 @@ function vfmath.define(specification,set,goodies) if n then t.next = offset + n elseif variants_done then - local vv = fci.vert_variants + local vv = fci.vvariants if vv then - t.vert_variants = vv + t.vvariants = vv end - local hv = fci.horiz_variants + local hv = fci.hvariants if hv then - t.horiz_variants = hv + t.hvariants = hv end else - local vv = fci.vert_variants + local vv = fci.vvariants if vv then for i=1,#vv do local vvi = vv[i] vvi.glyph = vvi.glyph + offset end - t.vert_variants = vv + t.vvariants = vv end - local hv = fci.horiz_variants + local hv = fci.hvariants if hv then for i=1,#hv do local hvi = hv[i] hvi.glyph = hvi.glyph + offset end - t.horiz_variants = hv + t.hvariants = hv end end characters[offset + index] = t diff --git a/tex/context/base/mkxl/node-aux.lmt b/tex/context/base/mkxl/node-aux.lmt index 1aeae3b45..0c9bfc837 100644 --- a/tex/context/base/mkxl/node-aux.lmt +++ b/tex/context/base/mkxl/node-aux.lmt @@ -221,7 +221,7 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob- n = copy_node(space) elseif fonts then -- depedency local parameters = fonts.hashes.identifiers[fnt].parameters - space = new_glue(parameters.space,parameters.space_stretch,parameters.space_shrink) + space = new_glue(parameters.space,parameters.spacestretch,parameters.spaceshrink) n = space end elseif template then @@ -354,8 +354,8 @@ end do local parcodes = nodes.parcodes - local hmodepar_code = parcodes.hmode_par - local vmodepar_code = parcodes.vmode_par + local hmodepar_code = parcodes.hmodepar + local vmodepar_code = parcodes.vmodepar local getnest = tex.getnest local getsubtype = nuts.getsubtype diff --git a/tex/context/base/mkxl/node-pro.lmt b/tex/context/base/mkxl/node-pro.lmt index bbcbc9bdc..f38e8280b 100644 --- a/tex/context/base/mkxl/node-pro.lmt +++ b/tex/context/base/mkxl/node-pro.lmt @@ -111,11 +111,6 @@ do local lineactions = tasks.actions("contributers") local adjustactions = tasks.actions("adjusters") - -- contribute_head : pre_box - -- pre_adjust_head : pre_adjust - -- just_box : box - -- post_adjust_head : adjust - -- this was the "contributers" callback but we changed the interface -- historically we use a different order than the callback @@ -133,7 +128,7 @@ do end end end - elseif where == "post_adjust" or where == "pre_adjust" then + elseif where == "postadjust" or where == "preadjust" then -- we use the same order as for lines return adjustactions(head,where,tail,index) end diff --git a/tex/context/base/mkxl/node-rul.lmt b/tex/context/base/mkxl/node-rul.lmt index 8fa02cc89..0d1a9548e 100644 --- a/tex/context/base/mkxl/node-rul.lmt +++ b/tex/context/base/mkxl/node-rul.lmt @@ -341,8 +341,15 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a end end + local first = 1 + local last = level + + if extra then + first = level + end + if mp and mp ~= "" then - for i=extra and level or 1,level do + for i=first,last do local r = usernutrule { width = wd, height = ht, @@ -369,7 +376,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a l = hpack_nodes(l,wd,"exactly") inject(l,wd,ht,dp) else - for i=extra and level or 1,level do + for i=first,last do local hd = (offset+(i-1)*dy)*e - m local ht = hd + rulethickness local dp = -hd + rulethickness diff --git a/tex/context/base/mkxl/node-ser.lmt b/tex/context/base/mkxl/node-ser.lmt index c14a3826f..333784803 100644 --- a/tex/context/base/mkxl/node-ser.lmt +++ b/tex/context/base/mkxl/node-ser.lmt @@ -52,9 +52,9 @@ local canbeignored = { } local canbechar = { - char = true, - small_char = true, - large_char = true, + char = true, + smallchar = true, + largechar = true, } local fieldtypes = table.setmetatableindex(function(t,k) @@ -119,7 +119,7 @@ local function to_table(n,flat,verbose,noattributes,done) for field, fieldtype in sortedhash(fields) do local value = n[field] if value then - if fieldtype == "attribute_list" or fieldtype == "attribute" then + if fieldtype == "attributelist" or fieldtype == "attribute" or fieldtype == "attribute_list" then if noattributes then result[value] = canbeignored[value] else diff --git a/tex/context/base/mkxl/node-typ.lmt b/tex/context/base/mkxl/node-typ.lmt new file mode 100644 index 000000000..c09fd5f67 --- /dev/null +++ b/tex/context/base/mkxl/node-typ.lmt @@ -0,0 +1,135 @@ +if not modules then modules = { } end modules ['node-typ'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- code has been moved to blob-ini.lua + +local typesetters = nodes.typesetters or { } +nodes.typesetters = typesetters + +local nuts = nodes.nuts +local tonode = nuts.tonode +local tonut = nuts.tonut + +local setlink = nuts.setlink +local setchar = nuts.setchar +local setattrlist = nuts.setattrlist + +local getfont = nuts.getfont + +local hpack_node_list = nuts.hpack +local vpack_node_list = nuts.vpack +local full_hpack_list = nuts.fullhpack + +local nodepool = nuts.pool +local new_glyph = nodepool.glyph +local new_glue = nodepool.glue + +local utfvalues = utf.values + +local currentfont = font.current +local currentattributes = nodes.currentattributes +local fontparameters = fonts.hashes.parameters + +-- when attrid == true then take from glyph or current else use the given value + +-- todo: glyphscale etc + +local function tonodes(str,fontid,spacing,templateglyph,attrid) -- quick and dirty + local head, prev = nil, nil + if not fontid then + fontid = templateglyph and getfont(templateglyph) or currentfont() + end + if attrid == true then + if templateglyph then + attrid = false -- we copy with the glyph + else + attrid = currentattributes() + end + end + local fp = fontparameters[fontid] + local s, p, m + if spacing then + s, p, m = spacing, 0, 0 + else + s, p, m = fp.space, fp.spacestretch, fp.spaceshrink + end + local spacedone = false + for c in utfvalues(str) do + local next + if c == 32 then + if not spacedone then + next = new_glue(s,p,m) + spacedone = true + end + elseif templateglyph then + next = copy_glyph(templateglyph) + setchar(next,c) + spacedone = false + else + next = new_glyph(fontid or 1,c) + spacedone = false + end + if not next then + -- nothing + elseif not head then + if attrid then + setattrlist(next,attrid) + end + head = next + else + if attrid then + setattrlist(next,attrid) + end + setlink(prev,next) + end + prev = next + end + return head +end + +local function tohpack(str,fontid,spacing) + return hpack_node_list(tonodes(str,fontid,spacing),"exactly") +end + +local function tohbox(str,fontid,spacing) + return full_hpack_list(tonodes(str,fontid,spacing),"exactly") +end + +local function tovpack(str,fontid,spacing) + -- vpack is just a hack, and a proper implementation is on the agenda + -- as it needs more info etc than currently available + return vpack_node_list(tonodes(str,fontid,spacing)) +end + +local tovbox = tovpack -- for now no vpack filter + +local tnuts = { } +nuts.typesetters = tnuts + +tnuts.tonodes = tonodes +tnuts.tohpack = tohpack +tnuts.tohbox = tohbox +tnuts.tovpack = tovpack +tnuts.tovbox = tovbox + +typesetters.tonodes = function(...) local h, b = tonodes(...) return tonode(h), b end +typesetters.tohpack = function(...) local h, b = tohpack(...) return tonode(h), b end +typesetters.tohbox = function(...) local h, b = tohbox (...) return tonode(h), b end +typesetters.tovpack = function(...) local h, b = tovpack(...) return tonode(h), b end +typesetters.tovbox = function(...) local h, b = tovbox (...) return tonode(h), b end + +typesetters.hpack = typesetters.tohpack -- obsolete +typesetters.hbox = typesetters.tohbox -- obsolete +typesetters.vpack = typesetters.tovpack -- obsolete + +-- context(nodes.typesetters.tohpack("Hello World!")) +-- context(nodes.typesetters.tohbox ("Hello World!")) +-- context(nodes.typesetters.tohpack("Hello World!",1,100*1024*10)) +-- context(nodes.typesetters.tohbox ("Hello World!",1,100*1024*10)) + +string.tonodes = function(...) return tonode(tonodes(...)) end -- quite convenient diff --git a/tex/context/base/mkxl/page-ini.lmt b/tex/context/base/mkxl/page-ini.lmt index ef34687c6..ec2278c01 100644 --- a/tex/context/base/mkxl/page-ini.lmt +++ b/tex/context/base/mkxl/page-ini.lmt @@ -361,10 +361,10 @@ implement { -- usage = "value", -- actions = function() -- local result = 0 --- if nodes.nuts.getspeciallist("contribute_head") then +-- if nodes.nuts.getspeciallist("contributehead") then -- result = result | 1 -- end --- if nodes.nuts.getspeciallist("page_head") then +-- if nodes.nuts.getspeciallist("pagehead") then -- result = result | 2 -- end -- return tokens.values.integer, result diff --git a/tex/context/base/mkxl/scrn-ref.lmt b/tex/context/base/mkxl/scrn-ref.lmt new file mode 100644 index 000000000..be298e2d1 --- /dev/null +++ b/tex/context/base/mkxl/scrn-ref.lmt @@ -0,0 +1,57 @@ +if not modules then modules = { } end modules ['scrn-ref'] = { + version = 1.001, + comment = "companion to scrn-int.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +interactions = interactions or { } +interactions.references = interactions.references or { } +local references = interactions.references + +local codeinjections = backends.codeinjections + +local identify = structures.references.identify + +local implement = interfaces.implement + +local function check(what) + if what and what ~= "" then + local set, bug = identify("",what) + return not bug and #set > 0 and set + end +end + +function references.setopendocumentaction(open) + local opendocument = check(open) + if opendocument then + codeinjections.registerdocumentopenaction(opendocument) + end +end + +function references.setclosedocumentaction(close) + local closedocument = check(close) + if closedocument then + codeinjections.registerdocumentcloseaction(closedocument) + end +end + +function references.setopenpageaction(open) + local openpage = check(open) + if openpage then + codeinjections.registerpageopenaction(openpage) + end +end + +function references.setclosepageaction(close) + local closepage = check(close) + if closepage then + codeinjections.registerpagecloseaction(closepage) + end +end + +implement { name = "setopendocumentaction", arguments = "string", actions = references.setopendocumentaction } +implement { name = "setclosedocumentaction", arguments = "string", actions = references.setclosedocumentaction } +implement { name = "setopenpageaction", arguments = "string", actions = references.setopenpageaction } +implement { name = "setclosepageaction", arguments = "string", actions = references.setclosepageaction } diff --git a/tex/context/base/mkxl/scrn-ref.mklx b/tex/context/base/mkxl/scrn-ref.mklx index d6fc6e127..ffe1fab16 100644 --- a/tex/context/base/mkxl/scrn-ref.mklx +++ b/tex/context/base/mkxl/scrn-ref.mklx @@ -13,7 +13,7 @@ \writestatus{loading}{ConTeXt Screen Macros / References} -\registerctxluafile{scrn-ref}{} +\registerctxluafile{scrn-ref}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/scrp-ini.lmt b/tex/context/base/mkxl/scrp-ini.lmt index b71a530a2..a8856f148 100644 --- a/tex/context/base/mkxl/scrp-ini.lmt +++ b/tex/context/base/mkxl/scrp-ini.lmt @@ -871,8 +871,8 @@ do if lastfont ~= font then local pf = parameters[font] space = pf.space - stretch = pf.space_stretch - shrink = pf.space_shrink + stretch = pf.spacestretch + shrink = pf.spaceshrink lastfont = font end return new_glue( diff --git a/tex/context/base/mkxl/spac-chr.lmt b/tex/context/base/mkxl/spac-chr.lmt index e38f2a30e..554dc0400 100644 --- a/tex/context/base/mkxl/spac-chr.lmt +++ b/tex/context/base/mkxl/spac-chr.lmt @@ -131,7 +131,7 @@ local function nbsp(head,current) if attr >= 1 and attr <= 3 then -- flushright head, current = inject_nobreak_space(0x00A0,head,current,para.space,0,0) else - head, current = inject_nobreak_space(0x00A0,head,current,para.space,para.space_stretch,para.space_shrink) + head, current = inject_nobreak_space(0x00A0,head,current,para.space,para.spacestretch,para.spaceshrink) end setsubtype(current,spaceskip_code) return head, current @@ -190,7 +190,7 @@ local methods = { head, current = remove_node(head,current,true) if not is_punctuation[char] then local p = fontparameters[font] - head, current = insertnodebefore(head,current,new_glue(p.space,p.space_stretch,p.space_shrink)) + head, current = insertnodebefore(head,current,new_glue(p.space,p.spacestretch,p.spaceshrink)) end end end diff --git a/tex/context/base/mkxl/spac-prf.lmt b/tex/context/base/mkxl/spac-prf.lmt index 2223c7730..c38cdc97b 100644 --- a/tex/context/base/mkxl/spac-prf.lmt +++ b/tex/context/base/mkxl/spac-prf.lmt @@ -269,9 +269,9 @@ end profiling.get = getprofile local function getpagelist() - local pagehead = texlists.page_head + local pagehead = texlists.pagehead if pagehead then - pagehead = tonut(texlists.page_head) + pagehead = tonut(texlists.pagehead) pagetail = find_node_tail(pagehead) else pagetail = nil diff --git a/tex/context/base/mkxl/spac-ver.lmt b/tex/context/base/mkxl/spac-ver.lmt index ca0544cf8..fcb1b7e7f 100644 --- a/tex/context/base/mkxl/spac-ver.lmt +++ b/tex/context/base/mkxl/spac-ver.lmt @@ -1054,7 +1054,7 @@ end -- implementation --- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display +-- alignment box begin_of_par vmodepar hmodepar insert penalty before_display after_display function vspacing.snapbox(n,how) local sv = snapmethods[how] @@ -1440,7 +1440,7 @@ do -- quit, we're not on the mvl else -- inefficient when we're at the end of a page - local c = tonut(texlists.page_head) + local c = tonut(texlists.pagehead) while c and c ~= n do local id = getid(c) if id == hlist_code then @@ -1486,7 +1486,7 @@ do -- local function getpagelist() if not pagehead then - pagehead = texlists.page_head + pagehead = texlists.pagehead if pagehead then pagehead = tonut(pagehead) pagetail = find_node_tail(pagehead) -- no texlists.page_tail yet-- no texlists.page_tail yet @@ -2263,7 +2263,7 @@ do function vspacing.getnofpreviouslines(head) if enabled then if not thead then - head = texlists.page_head + head = texlists.pagehead end local noflines = 0 if head then @@ -2314,7 +2314,7 @@ do if trace then local newdepth = outer.prevdepth local olddepth = newdepth - if not texlists.page_head then + if not texlists.pagehead then newdepth = ignoredepth texset("prevdepth",ignoredepth) outer.prevdepth = ignoredepth @@ -2322,7 +2322,7 @@ do report("page %i, prevdepth %p => %p",texgetcount("realpageno"),olddepth,newdepth) -- report("list %s",nodes.idsandsubtypes(head)) else - if not texlists.page_head then + if not texlists.pagehead then texset("prevdepth",ignoredepth) outer.prevdepth = ignoredepth end @@ -2353,7 +2353,7 @@ do end nest.prevdepth = depth elseif id == temp_code and texgetnest("ptr") == 0 then - local head = texgetlist("page_head") + local head = texgetlist("pagehead") if head then tail = getnodetail(head) if tail and tail.id == hlist_code then @@ -2472,11 +2472,11 @@ do -- check if in mvl if texgetnest("ptr") == 0 then -- this flushes the contributions - while getspeciallist("contribute_head") do + while getspeciallist("contributehead") do triggerbuildpage() end -- now we consult the last line (if present) - local head, tail = getspeciallist("page_head") + local head, tail = getspeciallist("pagehead") if tail then for n, id, subtype in treversenode, tail do if id == hlist_code then @@ -2521,7 +2521,7 @@ do -- interfaces.implement { -- name = "removelastline", -- actions = function() - -- local h, t = getspeciallist("page_head") + -- local h, t = getspeciallist("pagehead") -- if t and getid(t) == hlist_code and getsubtype(t) == line_code then -- local total = gettotal(t) -- h = remove_node(h,t,true) @@ -2663,10 +2663,10 @@ do -- interfaces.implement { -- name = "fakenextstrutline", -- actions = function() - -- local head = texlists.page_head + -- local head = texlists.pagehead -- if head then -- local head = remove_node(head,find_node_tail(head),true) - -- texlists.page_head = head + -- texlists.pagehead = head -- buildpage() -- end -- end @@ -2675,13 +2675,13 @@ do implement { name = "removelastline", actions = function() - local head = texlists.page_head + local head = texlists.pagehead if head then local tail = find_node_tail(head) if tail then -- maybe check for hlist subtype 1 local head = remove_node(head,tail,true) - texlists.page_head = head + texlists.pagehead = head buildpage() end end @@ -2691,7 +2691,7 @@ do implement { name = "showpagelist", -- will improve actions = function() - local head = texlists.page_head + local head = texlists.pagehead if head then print("start") while head do diff --git a/tex/context/base/mkxl/supp-box.lmt b/tex/context/base/mkxl/supp-box.lmt index 03bb54137..8a290b5ae 100644 --- a/tex/context/base/mkxl/supp-box.lmt +++ b/tex/context/base/mkxl/supp-box.lmt @@ -757,9 +757,9 @@ end implement { name = "lastlinewidth", actions = function() - local head = tex.lists.page_head + local head = tex.lists.pagehead -- list dimensions returns 3 value but we take the first - context(head and getdimensions(getlist(find_tail(tonut(tex.lists.page_head)))) or 0) + context(head and getdimensions(getlist(find_tail(tonut(tex.lists.pagehead)))) or 0) end } diff --git a/tex/context/base/mkxl/trac-jus.lmt b/tex/context/base/mkxl/trac-jus.lmt new file mode 100644 index 000000000..e9c8fac28 --- /dev/null +++ b/tex/context/base/mkxl/trac-jus.lmt @@ -0,0 +1,122 @@ +if not modules then modules = { } end modules ['trac-jus'] = { + version = 1.001, + comment = "companion to trac-jus.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local checkers = typesetters.checkers or { } +typesetters.checkers = checkers + +----- report_justification = logs.reporter("visualize","justification") + +local a_alignstate = attributes.private("alignstate") +local a_justification = attributes.private("justification") + +local nuts = nodes.nuts + +local getfield = nuts.getfield +local getlist = nuts.getlist +local getattr = nuts.getattr +local setattr = nuts.setattr +local setlist = nuts.setlist +local setlink = nuts.setlink +local getwidth = nuts.getwidth +local findtail = nuts.tail + +local nexthlist = nuts.traversers.hlist + +local getdimensions = nuts.dimensions +local copylist = nuts.copylist + +local tracedrule = nodes.tracers.pool.nuts.rule + +local nodepool = nuts.pool + +local new_hlist = nodepool.hlist +local new_kern = nodepool.kern + +local hlist_code = nodes.nodecodes.hlist + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local enableaction = nodes.tasks.enableaction + +local min_threshold = 0 +local max_threshold = 0 + +local function set(n) + enableaction("mvlbuilders", "typesetters.checkers.handler") + enableaction("vboxbuilders","typesetters.checkers.handler") + texsetattribute(a_justification,n or 1) + function typesetters.checkers.set(n) + texsetattribute(a_justification,n or 1) + end +end + +local function reset() + texsetattribute(a_justification,unsetvalue) +end + +checkers.set = set +checkers.reset = reset + +interfaces.implement { + name = "showjustification", + actions = set +} + +trackers.register("visualizers.justification", function(v) + if v then + set(1) + else + reset() + end +end) + +function checkers.handler(head) + for current in nexthlist, head do + if getattr(current,a_justification) == 1 then + setattr(current,a_justification,0) -- kind of reset + local width = getwidth(current) + if width > 0 then + local list = getlist(current) + if list then + local naturalwidth, naturalheight, naturaldepth = getdimensions(list) + local delta = naturalwidth - width + if naturalwidth == 0 or delta == 0 then + -- special box + elseif delta >= max_threshold then + local rule = new_hlist(tracedrule(delta,naturalheight,naturaldepth,getfield(list,"glueset") == 1 and "trace:dr" or "trace:db")) + setlink(findtail(list),rule) + setlist(current,list) + elseif delta <= min_threshold then + local alignstate = getattr(list,a_alignstate) + if alignstate == 1 then + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dc")) + setlink(rule,list) + setlist(current,rule) + elseif alignstate == 2 then + local lrule = new_hlist(tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy")) + local rrule = copylist(lrule) + setlink(lrule,list) + setlink(findtail(list),new_kern(delta/2),rrule) + setlist(current,lrule) + elseif alignstate == 3 then + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dm")) + setlink(findtail(list),new_kern(delta),rule) + setlist(current,list) + else + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dg")) + setlink(findtail(list),new_kern(delta),rule) + setlist(current,list) + end + end + end + end + end + end + return head +end diff --git a/tex/context/base/mkxl/trac-jus.mkxl b/tex/context/base/mkxl/trac-jus.mkxl index 3375e5ee7..387478cb1 100644 --- a/tex/context/base/mkxl/trac-jus.mkxl +++ b/tex/context/base/mkxl/trac-jus.mkxl @@ -13,7 +13,7 @@ \writestatus{loading}{ConTeXt Tracing Macros / Justification} -\registerctxluafile{trac-jus}{} +\registerctxluafile{trac-jus}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/typo-adj.lmt b/tex/context/base/mkxl/typo-adj.lmt index 53abe4f1d..31a2c2c78 100644 --- a/tex/context/base/mkxl/typo-adj.lmt +++ b/tex/context/base/mkxl/typo-adj.lmt @@ -52,7 +52,7 @@ local postactions = { } -- function nodes.handlers.adjusters(head,where,tail) --- if where == "pre_adjust" then +-- if where == "preadjust" then -- local a = getattr(tail,a_adjuster) -- if a then -- a = preactions[a] @@ -60,7 +60,7 @@ local postactions = { -- head = a(head,tail) -- end -- end --- elseif where == "post_adjust" then +-- elseif where == "postadjust" then -- local a = getattr(tail,a_adjuster) -- if a then -- a = postactions[a] @@ -75,12 +75,12 @@ local postactions = { -- end function nodes.handlers.adjusters(head,where,tail,index) - if where == "pre_adjust" then + if where == "preadjust" then local a = preactions[index] if a then head = a(head,tail) end - else -- if where == "post_adjust" then + else -- if where == "postadjust" then local a = postactions[index] if a then head = a(head,tail) diff --git a/tex/context/base/mkxl/typo-bld.lmt b/tex/context/base/mkxl/typo-bld.lmt index 31cc0bb59..9c83adede 100644 --- a/tex/context/base/mkxl/typo-bld.lmt +++ b/tex/context/base/mkxl/typo-bld.lmt @@ -231,10 +231,10 @@ end -- the check can go away -- Todo: contrib_head can be any head (kind of) not per se the page one so maybe I will --- intercept that in the engine with page_contribute_head or so. +-- intercept that in the engine with contributehead or so. function builders.buildpage_filter(groupcode) - local head = texlists.contribute_head + local head = texlists.contributehead if head then local done = false -- called quite often ... maybe time to remove timing @@ -246,8 +246,8 @@ function builders.buildpage_filter(groupcode) stoptiming(builders) -- -- doesn't work here (not passed on?) -- texset("pagegoal,texget("vsize") - texgetdimen("d_page_floats_inserted_top") - texgetdimen("d_page_floats_inserted_bottom") - texlists.contribute_head = head or nil -- needs checking - -- tex.setlist("contribute_head",head,head and nodes.tail(head)) + texlists.contributehead = head or nil -- needs checking + -- tex.setlist("contributehead",head,head and nodes.tail(head)) return done and head or true -- no return value needed else -- happens quite often diff --git a/tex/context/base/mkxl/typo-krn.lmt b/tex/context/base/mkxl/typo-krn.lmt index 450194767..bfd50062d 100644 --- a/tex/context/base/mkxl/typo-krn.lmt +++ b/tex/context/base/mkxl/typo-krn.lmt @@ -207,7 +207,7 @@ local function kern_injector(fillup,kern) if fillup then local g = new_glue(kern) setfield(g,"stretch",kern) - setfield(g,"stretch_order",1) + setfield(g,"stretchorder",1) return g else return new_kern(kern) @@ -538,7 +538,7 @@ function kerns.handler(head) elseif id == glue_code then local subtype = getsubtype(start) if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then - local width, stretch, shrink, stretch_order, shrink_order = getglue(start) + local width, stretch, shrink, stretchorder, shrinkorder = getglue(start) if width > 0 then local w = width + gluefactor * width * krn stretch = stretch * w / width @@ -546,10 +546,10 @@ function kerns.handler(head) if fillup then stretch = 2 * stretch shrink = 2 * shrink - stretch_order = 1 - -- shrink_order = 1 ? + stretchorder = 1 + -- shrinkorder = 1 ? end - setglue(start,w,stretch,shrink,stretch_order,shrink_order) + setglue(start,w,stretch,shrink,stretchorder,shrinkorder) end end bound = false diff --git a/tex/context/base/mkxl/typo-mar.lmt b/tex/context/base/mkxl/typo-mar.lmt index f8c135fa7..b590c9ecf 100644 --- a/tex/context/base/mkxl/typo-mar.lmt +++ b/tex/context/base/mkxl/typo-mar.lmt @@ -806,7 +806,7 @@ local function flushed(scope,parent) -- current is hlist return done, continue end --- only when group : vbox|vmode_par +-- only when group : vbox|vmodepar -- only when subtype : line, box (no indent alignment cell) local function handler(scope,head,group) @@ -884,9 +884,9 @@ function margins.globalhandler(head,group) -- check group report_margindata("ignored 1, group %a, stored %s, inhibit %a",group,nofstored,inhibit) end return head - elseif group == "hmode_par" then + elseif group == "hmodepar" then return handler(v_global,head,group) - elseif group == "vmode_par" then -- experiment (for alignments) + elseif group == "vmodepar" then -- experiment (for alignments) return handler(v_global,head,group) -- this needs checking as we then get quite some one liners to process and -- we cannot look ahead then: diff --git a/tex/context/base/mkxl/typo-par.mkxl b/tex/context/base/mkxl/typo-par.mkxl index 22450e76e..077d3566c 100644 --- a/tex/context/base/mkxl/typo-par.mkxl +++ b/tex/context/base/mkxl/typo-par.mkxl @@ -24,7 +24,7 @@ \unprotect %registerctxluafile{node-ltp}{optimize} -\registerctxluafile{node-ltp}{} +\registerctxluafile{node-ltp}{autosuffix} % this one has to be updated! \registerctxluafile{trac-par}{} \registerctxluafile{typo-par}{} diff --git a/tex/context/fonts/mkiv/type-imp-adobegaramond.mkiv b/tex/context/fonts/mkiv/type-imp-adobegaramond.mkiv new file mode 100644 index 000000000..88ad5ed2c --- /dev/null +++ b/tex/context/fonts/mkiv/type-imp-adobegaramond.mkiv @@ -0,0 +1,42 @@ +%D \module +%D [ file=type-imp-adobegaramond, +%D version=2021.10.30, +%D title=\CONTEXT\ Typescript Macros, +%D subtitle=Adobe Garamond, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + + +\starttypescriptcollection[adobegaramond] + + \starttypescript [\s!serif] [adobegaramond] [\s!name] + \setups[font:fallback:serif] + \definefontsynonym [\s!Serif] [\s!file:AGaramondPro-Regular] + \definefontsynonym [\s!SerifItalic] [\s!file:AGaramondPro-Italic] + \definefontsynonym [\s!SerifBold] [\s!file:AGaramondPro-Semibold] + \stoptypescript + + \starttypescript [\s!sans] [frutiger] [\s!name] + \setups[font:fallback:sans] + \definefontsynonym [\s!Sans] [\s!file:FrutigerLTStd-Roman] + \definefontsynonym [\s!SansItalic] [\s!file:FrutigerLTStd-Italic] + \definefontsynonym [\s!SansBold] [\s!file:FrutigerLTStd-Bold] + \stoptypescript + + \starttypescript [\s!math] [garamond-math] [\s!name] + \loadfontgoodies[garamond-math] + \definefontsynonym [\s!MathRoman] [\s!file:garamond-math.otf] [\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=garamond-math] + \stoptypescript + + \starttypescript[adobegaramond] + \definetypeface [adobegaramond] [\s!rm] [\s!serif] [adobegaramond] [\s!default] + \definetypeface [adobegaramond] [\s!ss] [\s!sans] [frutiger] [\s!default] [\s!rscale=0.85] + \definetypeface [adobegaramond] [\s!mm] [\s!math] [garamond-math] [\s!default] + \stoptypescript + +\stoptypescriptcollection diff --git a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv index 05ac2f1fa..03bb91989 100644 --- a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv +++ b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv @@ -66,8 +66,8 @@ \stoptypescript \starttypescript [\s!math] [ebgaramond] [\s!name] - \loadfontgoodies[ebgaramond] - \definefontsynonym [\s!MathRoman] [\s!file:garamond-math.otf] [\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=ebgaramond] + \loadfontgoodies[garamond-math] + \definefontsynonym [\s!MathRoman] [\s!file:garamond-math.otf] [\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=garamond-math] \stoptypescript \starttypescript[ebgaramond] diff --git a/tex/context/interface/mkii/keys-pe.xml b/tex/context/interface/mkii/keys-pe.xml index 76f6d8117..70fc55c34 100644 --- a/tex/context/interface/mkii/keys-pe.xml +++ b/tex/context/interface/mkii/keys-pe.xml @@ -1288,6 +1288,7 @@ <cd:constant name='tab' value='تب'/> <cd:constant name='text' value='متن'/> <cd:constant name='textalign' value='textalign'/> + <cd:constant name='textalternative' value='textalternative'/> <cd:constant name='textcolor' value='رنگمتن'/> <cd:constant name='textcommand' value='فرمانمتن'/> <cd:constant name='textdistance' value='فاصلهمتن'/> diff --git a/tex/context/modules/mkiv/s-math-characters.lua b/tex/context/modules/mkiv/s-math-characters.lua index 61b2c8808..fc697cae5 100644 --- a/tex/context/modules/mkiv/s-math-characters.lua +++ b/tex/context/modules/mkiv/s-math-characters.lua @@ -157,8 +157,8 @@ local alllookups = collectalllookups(tfmdata,"math","dflt") -- skip else local next_sizes = char.next - local v_variants = char.vert_variants - local h_variants = char.horiz_variants + local vvariants = char.vvariants or char.vert_variants + local hvariants = char.hvariants or char.horiz_variants local mathclass = info.mathclass local mathspec = info.mathspec local mathsymbol = info.mathsymbol @@ -208,29 +208,29 @@ local alllookups = collectalllookups(tfmdata,"math","dflt") done[next_sizes] = true context.showmathcharactersnextentry(n,f_unicode(next_sizes),next_sizes) next_sizes = characters[next_sizes] - v_variants = next_sizes.vert_variants or v_variants - h_variants = next_sizes.horiz_variants or h_variants + vvariants = next_sizes.vvariants or next_sizes.vert_variants or vvariants + hvariants = next_sizes.hvariants or next_sizes.horiz_variants or hvariants if next_sizes then next_sizes = next_sizes.next end end end context.showmathcharactersstopnext() - if h_variants or v_variants then + if hvariants or vvariants then context.showmathcharactersbetweennextandvariants() end end - if h_variants then + if hvariants then context.showmathcharactersstarthvariants() - for i=1,#h_variants do -- we might go top-down in the original - local vi = h_variants[i] + for i=1,#hvariants do -- we might go top-down in the original + local vi = hvariants[i] context.showmathcharactershvariantsentry(i,f_unicode(vi.glyph),vi.glyph) end context.showmathcharactersstophvariants() - elseif v_variants then + elseif vvariants then context.showmathcharactersstartvvariants() - for i=1,#v_variants do - local vi = v_variants[#v_variants-i+1] + for i=1,#vvariants do + local vi = vvariants[#vvariants-i+1] context.showmathcharactersvvariantsentry(i,f_unicode(vi.glyph),vi.glyph) end context.showmathcharactersstopvvariants() diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 7ac66bfc7..e50c388b9 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 2021-11-30 19:43 +-- merge date : 2021-12-03 15:17 do -- begin closure to overcome local limits and interference |