From 2bca80bc96d0182956e57c51b5d4977f714bed5c Mon Sep 17 00:00:00 2001 From: Context Git Mirror Bot Date: Thu, 2 Jun 2016 23:03:30 +0200 Subject: 2016-06-02 21:33:00 --- tex/context/base/context-version.pdf | Bin 4250 -> 4245 bytes tex/context/base/mkii/mult-de.mkii | 1 + tex/context/base/mkii/mult-en.mkii | 1 + tex/context/base/mkii/mult-fr.mkii | 1 + tex/context/base/mkii/mult-it.mkii | 1 + tex/context/base/mkii/mult-nl.mkii | 1 + tex/context/base/mkii/mult-pe.mkii | 1 + tex/context/base/mkii/mult-ro.mkii | 1 + tex/context/base/mkiv/anch-pos.lua | 9 + tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/context-todo.tex | 6 +- tex/context/base/mkiv/context.mkiv | 2 +- tex/context/base/mkiv/font-ext.lua | 23 +- tex/context/base/mkiv/font-gds.lua | 941 --------------------- tex/context/base/mkiv/font-lib.mkvi | 6 +- tex/context/base/mkiv/font-otj.lua | 2 + tex/context/base/mkiv/font-sel.lua | 4 +- tex/context/base/mkiv/good-ctx.lua | 275 ++++++ tex/context/base/mkiv/good-gen.lua | 208 +++++ tex/context/base/mkiv/good-ini.lua | 349 ++++++++ tex/context/base/mkiv/good-mth.lua | 173 ++++ tex/context/base/mkiv/layo-ini.lua | 8 +- tex/context/base/mkiv/lxml-tab.lua | 6 +- tex/context/base/mkiv/lxml-tex.lua | 3 + tex/context/base/mkiv/math-map.lua | 4 + tex/context/base/mkiv/mult-def.lua | 4 + tex/context/base/mkiv/page-mix.lua | 3 - tex/context/base/mkiv/spac-ali.lua | 2 +- tex/context/base/mkiv/spac-ver.mkiv | 16 +- tex/context/base/mkiv/status-files.pdf | Bin 9274 -> 9080 bytes tex/context/base/mkiv/status-lua.pdf | Bin 268373 -> 268642 bytes tex/context/base/mkiv/trac-vis.lua | 7 +- tex/context/base/mkiv/typo-mar.lua | 332 +++----- tex/context/base/mkiv/typo-mar.mkiv | 6 +- tex/context/interface/mkii/keys-cs.xml | 1 + tex/context/interface/mkii/keys-de.xml | 1 + tex/context/interface/mkii/keys-en.xml | 1 + tex/context/interface/mkii/keys-fr.xml | 1 + tex/context/interface/mkii/keys-it.xml | 1 + tex/context/interface/mkii/keys-nl.xml | 1 + tex/context/interface/mkii/keys-pe.xml | 1 + tex/context/interface/mkii/keys-ro.xml | 1 + tex/context/interface/mkiv/i-context.pdf | Bin 820931 -> 820812 bytes tex/context/interface/mkiv/i-readme.pdf | Bin 60791 -> 60787 bytes tex/generic/context/luatex/luatex-fonts-merged.lua | 2 +- 45 files changed, 1235 insertions(+), 1173 deletions(-) delete mode 100644 tex/context/base/mkiv/font-gds.lua create mode 100644 tex/context/base/mkiv/good-ctx.lua create mode 100644 tex/context/base/mkiv/good-gen.lua create mode 100644 tex/context/base/mkiv/good-ini.lua create mode 100644 tex/context/base/mkiv/good-mth.lua (limited to 'tex') diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf index 11024640d..50c1120d2 100644 Binary files a/tex/context/base/context-version.pdf and b/tex/context/base/context-version.pdf differ diff --git a/tex/context/base/mkii/mult-de.mkii b/tex/context/base/mkii/mult-de.mkii index 0762fadfc..dbadca7c5 100644 --- a/tex/context/base/mkii/mult-de.mkii +++ b/tex/context/base/mkii/mult-de.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stack} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{start} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{status} diff --git a/tex/context/base/mkii/mult-en.mkii b/tex/context/base/mkii/mult-en.mkii index a16b87a48..751235942 100644 --- a/tex/context/base/mkii/mult-en.mkii +++ b/tex/context/base/mkii/mult-en.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stack} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{start} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{state} diff --git a/tex/context/base/mkii/mult-fr.mkii b/tex/context/base/mkii/mult-fr.mkii index 6c71d4aad..aff330d76 100644 --- a/tex/context/base/mkii/mult-fr.mkii +++ b/tex/context/base/mkii/mult-fr.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stack} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{demarre} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{etat} diff --git a/tex/context/base/mkii/mult-it.mkii b/tex/context/base/mkii/mult-it.mkii index a875555bd..2c7dd13e9 100644 --- a/tex/context/base/mkii/mult-it.mkii +++ b/tex/context/base/mkii/mult-it.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stack} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{inizia} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{stato} diff --git a/tex/context/base/mkii/mult-nl.mkii b/tex/context/base/mkii/mult-nl.mkii index efc0d2be3..163628a2f 100644 --- a/tex/context/base/mkii/mult-nl.mkii +++ b/tex/context/base/mkii/mult-nl.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitsoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stapel} +\setinterfaceconstant{stackname}{stapelnaam} \setinterfaceconstant{start}{start} \setinterfaceconstant{starter}{opener} \setinterfaceconstant{state}{status} diff --git a/tex/context/base/mkii/mult-pe.mkii b/tex/context/base/mkii/mult-pe.mkii index 7e5c53791..c2db11315 100644 --- a/tex/context/base/mkii/mult-pe.mkii +++ b/tex/context/base/mkii/mult-pe.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{شکافتن‌آفست} \setinterfaceconstant{spot}{لکه} \setinterfaceconstant{stack}{توده} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{شروع} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{وضعیت} diff --git a/tex/context/base/mkii/mult-ro.mkii b/tex/context/base/mkii/mult-ro.mkii index f7121f703..9698bffa5 100644 --- a/tex/context/base/mkii/mult-ro.mkii +++ b/tex/context/base/mkii/mult-ro.mkii @@ -1160,6 +1160,7 @@ \setinterfaceconstant{splitoffset}{splitoffset} \setinterfaceconstant{spot}{spot} \setinterfaceconstant{stack}{stack} +\setinterfaceconstant{stackname}{stackname} \setinterfaceconstant{start}{start} \setinterfaceconstant{starter}{starter} \setinterfaceconstant{state}{stare} diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua index 77816111d..2cb2e70ee 100644 --- a/tex/context/base/mkiv/anch-pos.lua +++ b/tex/context/base/mkiv/anch-pos.lua @@ -468,6 +468,15 @@ function jobpositions.enhance(name) enhance(tobesaved[name]) end +function jobpositions.gettobesaved(name,tag) + local t = tobesaved[name] + if t and tag then + return t[tag] + else + return t + end +end + -- scanners.pos = function(name,t) -- name t -- local name = scanstring() -- tobesaved[name] = scanstring() diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 4c62d968e..6e7b66a5b 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2016.05.31 09:02} +\newcontextversion{2016.06.02 21:28} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/context-todo.tex b/tex/context/base/mkiv/context-todo.tex index 0e69b3df8..4df9dc816 100644 --- a/tex/context/base/mkiv/context-todo.tex +++ b/tex/context/base/mkiv/context-todo.tex @@ -9,9 +9,6 @@ \subsubject{\LUATEX} \startitemize - \startitem - head||tail cleanup in disc nodes (get rid of temp i.e.\ delay till linebreak) - \stopitem \startitem cleanup passive nodes \stopitem @@ -46,6 +43,9 @@ \startitem play with par callback and properties \stopitem + \startitem + add flag to font for math engine + \stopitem \startitem get rid of components \stopitem diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 66946af45..06455ca91 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2016.05.31 09:02} +\edef\contextversion{2016.06.02 21:28} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/mkiv/font-ext.lua b/tex/context/base/mkiv/font-ext.lua index 61e8c8179..7ab11ffb0 100644 --- a/tex/context/base/mkiv/font-ext.lua +++ b/tex/context/base/mkiv/font-ext.lua @@ -36,6 +36,7 @@ local fontdata = hashes.identifiers local allocate = utilities.storage.allocate local settings_to_array = utilities.parsers.settings_to_array local getparameters = utilities.parsers.getparameters +local gettexdimen = tex.getdimen local setmetatableindex = table.setmetatableindex @@ -625,12 +626,20 @@ local function manipulatedimensions(tfmdata,key,value) if type(value) == "string" and value ~= "" then local characters = tfmdata.characters local parameters = tfmdata.parameters - local emwidth = parameters.quad - local exheight = parameters.xheight - local spec = settings_to_array(value) - local width = (spec[1] or 0) * emwidth - local height = (spec[2] or 0) * exheight - local depth = (spec[3] or 0) * exheight + local emwidth = parameters.quad + local exheight = parameters.xheight + local width = 0 + local height = 0 + local depth = 0 + if value == "strut" then + height = gettexdimen("strutht") + depth = gettexdimen("strutdp") + else + local spec = settings_to_array(value) + width = (spec[1] or 0) * emwidth + height = (spec[2] or 0) * exheight + depth = (spec[3] or 0) * exheight + end if width > 0 then local resources = tfmdata.resources local additions = { } @@ -687,7 +696,7 @@ local function manipulatedimensions(tfmdata,key,value) elseif height > 0 and depth > 0 then for unicode, old_c in next, characters do old_c.height = height - old_c.depth = depth + old_c.depth = depth end elseif height > 0 then for unicode, old_c in next, characters do diff --git a/tex/context/base/mkiv/font-gds.lua b/tex/context/base/mkiv/font-gds.lua deleted file mode 100644 index c24bef315..000000000 --- a/tex/context/base/mkiv/font-gds.lua +++ /dev/null @@ -1,941 +0,0 @@ -if not modules then modules = { } end modules ['font-gds'] = { - version = 1.000, - comment = "companion to font-gds.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- depends on ctx - -local type, next, tonumber = type, next, tonumber -local gmatch, lower, find, splitup = string.gmatch, string.lower, string.find, string.splitup - -local fonts = fonts -local nodes = nodes -local attributes = attributes -local node = node - -local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) -local report_goodies = logs.reporter("fonts","goodies") - -local allocate = utilities.storage.allocate -local setmetatableindex = table.setmetatableindex - -local implement = interfaces.implement - -local texsp = tex.sp -local formatters = string.formatters - -local otf = fonts.handlers.otf -local afm = fonts.handlers.afm -local tfm = fonts.handlers.tfm - -local registerotffeature = otf.features.register -local registerafmfeature = afm.features.register -local registertfmfeature = tfm.features.register - -local fontgoodies = fonts.goodies or { } -fonts.goodies = fontgoodies - -local typefaces = fonts.typefaces or allocate() -fonts.typefaces = typefaces - -local data = fontgoodies.data or allocate() -fontgoodies.data = data - -local list = fontgoodies.list or { } -fontgoodies.list = list -- no allocate as we want to see what is there - -local addotffeature = otf.enhancers.addfeature - -local findfile = resolvers.findfile - -local glyph_code = nodes.nodecodes.glyph - -local nuts = nodes.nuts -local tonut = nuts.tonut -local getfont = nuts.getfont -local getchar = nuts.getchar -local getattr = nuts.getattr -local traverse_id = nuts.traverse_id - -function fontgoodies.report(what,trace,goodies) - if trace_goodies or trace then - local whatever = goodies[what] - if whatever then - report_goodies("goodie %a found in %a",what,goodies.name) - end - end -end - -local function loadgoodies(filename) -- maybe a merge is better - local goodies = data[filename] -- we assume no suffix is given - if goodies ~= nil then - -- found or tagged unfound - elseif type(filename) == "string" then - local fullname = findfile(file.addsuffix(filename,"lfg")) or "" -- prefered suffix - if fullname == "" then - fullname = findfile(file.addsuffix(filename,"lua")) or "" -- fallback suffix - end - if fullname == "" then - report_goodies("goodie file '%s.lfg' is not found",filename) - data[filename] = false -- signal for not found - else - goodies = dofile(fullname) or false - if not goodies then - report_goodies("goodie file %a is invalid",fullname) - return nil - elseif trace_goodies then - report_goodies("goodie file %a is loaded",fullname) - end - goodies.name = goodies.name or "no name" - for name, fnc in next, list do - if trace_goodies then - report_goodies("handling goodie %a",name) - end - fnc(goodies) - end - goodies.initialized = true - data[filename] = goodies - end - end - return goodies -end - -function fontgoodies.register(name,fnc) -- will be a proper sequencer - list[name] = fnc -end - -fontgoodies.load = loadgoodies - --- register goodies file - -local function setgoodies(tfmdata,value) - local goodies = tfmdata.goodies - if not goodies then -- actually an error - goodies = { } - tfmdata.goodies = goodies - end - for filename in gmatch(value,"[^, ]+") do - -- we need to check for duplicates - local ok = loadgoodies(filename) - if ok then - if trace_goodies then - report_goodies("assigning goodie %a",filename) - end - goodies[#goodies+1] = ok - end - end -end - --- this will be split into good-* files and this file might become good-ini.lua - --- featuresets - -local function flattenedfeatures(t,tt) - -- first set value dominates - local tt = tt or { } - for i=1,#t do - local ti = t[i] - if type(ti) == "table" then - flattenedfeatures(ti,tt) - elseif tt[ti] == nil then - tt[ti] = true - end - end - for k, v in next, t do - if type(k) ~= "number" then -- not tonumber(k) - if type(v) == "table" then - flattenedfeatures(v,tt) - elseif tt[k] == nil then - tt[k] = v - end - end - end - return tt -end - --- fonts.features.flattened = flattenedfeatures - -local function prepare_features(goodies,name,set) - if set then - local ff = flattenedfeatures(set) - local fullname = goodies.name .. "::" .. name - local n, s = fonts.specifiers.presetcontext(fullname,"",ff) - goodies.featuresets[name] = s -- set - if trace_goodies then - report_goodies("feature set %a gets number %a and name %a",name,n,fullname) - end - return n - end -end - -fontgoodies.prepare_features = prepare_features - -local function initialize(goodies) - local featuresets = goodies.featuresets - if featuresets then - if trace_goodies then - report_goodies("checking featuresets in %a",goodies.name) - end - for name, set in next, featuresets do - prepare_features(goodies,name,set) - end - end -end - -fontgoodies.register("featureset",initialize) - -local function setfeatureset(tfmdata,set,features) - local goodies = tfmdata.goodies -- shared ? - if goodies then - local properties = tfmdata.properties - local what - for i=1,#goodies do - -- last one wins - local g = goodies[i] - what = g.featuresets and g.featuresets[set] or what - end - if what then - for feature, value in next, what do - if features[feature] == nil then - features[feature] = value - end - end - properties.mode = what.mode or properties.mode - end - end -end - --- postprocessors (we could hash processor and share code) - -function fontgoodies.registerpostprocessor(tfmdata,f,prepend) - local postprocessors = tfmdata.postprocessors - if not postprocessors then - tfmdata.postprocessors = { f } - elseif prepend then - table.insert(postprocessors,f,1) - else - table.insert(postprocessors,f) - end -end - -local function setpostprocessor(tfmdata,processor) - local goodies = tfmdata.goodies - if goodies and type(processor) == "string" then - local found = { } - local asked = utilities.parsers.settings_to_array(processor) - for i=1,#goodies do - local g = goodies[i] - local p = g.postprocessors - if p then - for i=1,#asked do - local a = asked[i] - local f = p[a] - if type(f) == "function" then - found[a] = f - end - end - end - end - local postprocessors = tfmdata.postprocessors or { } - for i=1,#asked do - local a = asked[i] - local f = found[a] - if f then - postprocessors[#postprocessors+1] = f - end - end - if #postprocessors > 0 then - tfmdata.postprocessors = postprocessors - end - end -end - --- colorschemes - -local colorschemes = fontgoodies.colorschemes or allocate { } -fontgoodies.colorschemes = colorschemes -colorschemes.data = colorschemes.data or { } - -local function setcolorscheme(tfmdata,scheme) - if type(scheme) == "string" then - local goodies = tfmdata.goodies - -- todo : check for already defined in shared - if goodies then - local what - for i=1,#goodies do - -- last one counts - local g = goodies[i] - what = g.colorschemes and g.colorschemes[scheme] or what - end - if type(what) == "table" then - -- this is font bound but we can share them if needed - -- just as we could hash the conversions (per font) - local hash = tfmdata.resources.unicodes - local reverse = { } - local characters = tfmdata.characters - for i=1,#what do - local w = what[i] - for j=1,#w do - local name = w[j] - if name == "*" then - -- inefficient but only used for tracing anyway - for _, unicode in next, hash do - reverse[unicode] = i - end - elseif type(name) == "number" then - reverse[name] = i - elseif find(name,":",1,true) then - local start, stop = splitup(name,":") - start = tonumber(start) - stop = tonumber(stop) - if start and stop then - -- limited usage: we only deal with non reassigned - -- maybe some day I'll also support the ones with a - -- tounicode in this range - for unicode=start,stop do - if characters[unicode] then - reverse[unicode] = i - end - end - end - else - local unicode = hash[name] - if unicode then - reverse[unicode] = i - end - end - end - end - tfmdata.properties.colorscheme = reverse - return - end - end - end - tfmdata.properties.colorscheme = false -end - -local fontproperties = fonts.hashes.properties - -local a_colorscheme = attributes.private('colorscheme') -local setnodecolor = nodes.tracers.colors.set - --- function colorschemes.coloring(head) --- local lastfont, lastscheme --- local done = false --- for n in traverse_id(glyph_code,tonut(head)) do --- local a = getattr(n,a_colorscheme) --- if a then --- local f = getfont(n) --- if f ~= lastfont then --- lastscheme = fontproperties[f].colorscheme --- lastfont = f --- end --- if lastscheme then --- local sc = lastscheme[getchar(n)] --- if sc then --- done = true --- setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow --- end --- end --- end --- end --- return head, done --- end - --- seldom used, mostly in manuals, so non critical .. anyhow, somewhat faster: - --- function colorschemes.coloring(head) --- local lastfont = nil --- local lastattr = nil --- local lastscheme = nil --- local lastprefix = nil --- local done = nil --- for n in traverse_id(glyph_code,tonut(head)) do --- local a = getattr(n,a_colorscheme) --- if a then --- if a ~= lastattr then --- lastattr = a --- lastprefix = "colorscheme:" .. a .. ":" --- end --- local f = getfont(n) --- if f ~= lastfont then --- lastfont = f --- lastscheme = fontproperties[f].colorscheme --- end --- if lastscheme then --- local sc = lastscheme[getchar(n)] --- if sc then --- setnodecolor(n,lastprefix .. sc) -- slow --- done = true --- end --- end --- end --- end --- return head, done --- end - --- ok, in case we have hundreds of pages colored: - -local cache = { } -- this could be a weak table - -setmetatableindex(cache,function(t,a) - local v = { } - setmetatableindex(v,function(t,c) - local v = "colorscheme:" .. a .. ":" .. c - t[c] = v - return v - end) - t[a]= v - return v -end) - -function colorschemes.coloring(head) - local lastfont = nil - local lastattr = nil - local lastcache = nil - local lastscheme = nil - local done = nil - for n in traverse_id(glyph_code,tonut(head)) do - local a = getattr(n,a_colorscheme) - if a then - local f = getfont(n) - if f ~= lastfont then - lastfont = f - lastscheme = fontproperties[f].colorscheme - end - if a ~= lastattr then - lastattr = a - lastcache = cache[a] - end - if lastscheme then - local sc = lastscheme[getchar(n)] - if sc then - setnodecolor(n,lastcache[sc]) -- we could inline this one - done = true - end - end - end - end - return head, done -end - -function colorschemes.enable() - nodes.tasks.appendaction("processors","fonts","fonts.goodies.colorschemes.coloring") - function colorschemes.enable() end -end - -local function setextrafeatures(tfmdata) - local goodies = tfmdata.goodies - if goodies then - for i=1,#goodies do - local g = goodies[i] - local f = g.features - if f then - for feature, specification in next, f do - addotffeature(tfmdata.shared.rawdata,feature,specification) - registerotffeature { - name = feature, - description = formatters["extra: %s"](feature) - } - end - end - end - end -end - -local function setextensions(tfmdata) - local goodies = tfmdata.goodies - if goodies then - for i=1,#goodies do - local g = goodies[i] - local e = g.extensions - if e then - local goodie = g.name or "unknown" - for i=1,#e do - local name = "extension-" .. i - -- report_goodies("adding extension %s from %s",name,goodie) - otf.enhancers.addfeature(tfmdata.shared.rawdata,name,e[i]) - end - end - end - end -end - --- installation - -local goodies_specification = { - name = "goodies", - description = "goodies on top of built in features", - initializers = { - position = 1, - base = setgoodies, - node = setgoodies, - } -} - -registerotffeature(goodies_specification) -registerafmfeature(goodies_specification) -registertfmfeature(goodies_specification) - --- maybe more of the following could be for type one too - -registerotffeature { - name = "extrafeatures", - description = "extra features", - default = true, - initializers = { - position = 2, - base = setextrafeatures, - node = setextrafeatures, - } -} - -registerotffeature { - name = "extensions", - description = "extensions to features", - default = true, - initializers = { - position = 2, - base = setextensions, - node = setextensions, - } -} - -registerotffeature { - name = "featureset", - description = "goodie feature set", - initializers = { - position = 3, - base = setfeatureset, - node = setfeatureset, - } -} - -registerotffeature { - name = "colorscheme", - description = "goodie color scheme", - initializers = { - base = setcolorscheme, - node = setcolorscheme, - } -} - -registerotffeature { - name = "postprocessor", - description = "goodie postprocessor", - initializers = { - base = setpostprocessor, - node = setpostprocessor, - } -} - --- experiment, we have to load the definitions immediately as they precede --- the definition so they need to be initialized in the typescript - -local function initialize(goodies) - local mathgoodies = goodies.mathematics - if mathgoodies then - local virtuals = mathgoodies.virtuals - local mapfiles = mathgoodies.mapfiles - local maplines = mathgoodies.maplines - if virtuals then - for name, specification in next, virtuals do - -- beware, they are all constructed - mathematics.makefont(name,specification,goodies) - end - end - if mapfiles then - for i=1,#mapfiles do - fonts.mappings.loadfile(mapfiles[i]) -- todo: backend function - end - end - if maplines then - for i=1,#maplines do - fonts.mappings.loadline(maplines[i]) -- todo: backend function - end - end - end -end - -fontgoodies.register("mathematics", initialize) - --- the following takes care of explicit file specifications --- --- files = { --- name = "antykwapoltawskiego", --- list = { --- ["AntPoltLtCond-Regular.otf"] = { --- -- name = "antykwapoltawskiego", --- style = "regular", --- weight = "light", --- width = "condensed", --- }, --- }, --- } - --- math italics (not rteally needed) --- --- it would be nice to have a \noitalics\font option - -local function initialize(tfmdata) - local goodies = tfmdata.goodies - if goodies then - local shared = tfmdata.shared - for i=1,#goodies do - local mathgoodies = goodies[i].mathematics - if mathgoodies then - local mathitalics = mathgoodies.italics - if mathitalics then - local properties = tfmdata.properties - if properties.setitalics then - mathitalics = mathitalics[file.nameonly(properties.name)] or mathitalics - if mathitalics then - if trace_goodies then - report_goodies("loading mathitalics for font %a",properties.name) - end - local corrections = mathitalics.corrections - local defaultfactor = mathitalics.defaultfactor - -- properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change) - if corrections then - fontgoodies.registerpostprocessor(tfmdata, function(tfmdata) -- this is another tfmdata (a copy) - -- better make a helper so that we have less code being defined - local properties = tfmdata.properties - local parameters = tfmdata.parameters - local characters = tfmdata.characters - properties.mathitalic_defaultfactor = defaultfactor - properties.mathitalic_defaultvalue = defaultfactor * parameters.quad - if trace_goodies then - report_goodies("assigning mathitalics for font %a",properties.name) - end - local quad = parameters.quad - local hfactor = parameters.hfactor - for k, v in next, corrections do - local c = characters[k] - if c then - if v > -1 and v < 1 then - c.italic = v * quad - else - c.italic = v * hfactor - end - else - report_goodies("invalid mathitalics entry %U for font %a",k,properties.name) - end - end - end) - end - return -- maybe not as these can accumulate - end - end - end - end - end - end -end - -registerotffeature { - name = "mathitalics", - description = "additional math italic corrections", - -- default = true, - initializers = { - base = initialize, - node = initialize, - } -} - --- fontgoodies.register("mathitalics", initialize) - --- files - -local function initialize(goodies) - local files = goodies.files - if files then - fonts.names.register(files) - end -end - -fontgoodies.register("files", initialize) - --- some day we will have a define command and then we can also do some --- proper tracing --- --- fonts.typefaces["antykwapoltawskiego-condensed"] = { --- shortcut = "rm", --- shape = "serif", --- fontname = "antykwapoltawskiego", --- normalweight = "light", --- boldweight = "medium", --- width = "condensed", --- size = "default", --- features = "default", --- } - -local function initialize(goodies) - local typefaces = goodies.typefaces - if typefaces then - local ft = fonts.typefaces - for k, v in next, typefaces do - ft[k] = v - end - end -end - -fontgoodies.register("typefaces", initialize) - -local compositions = { } - -function fontgoodies.getcompositions(tfmdata) - return compositions[file.nameonly(tfmdata.properties.filename or "")] -end - -local function initialize(goodies) - local gc = goodies.compositions - if gc then - for k, v in next, gc do - compositions[k] = v - end - end -end - -fontgoodies.register("compositions", initialize) - --- extra treatments (on top of defaults): \loadfontgoodies[mytreatments] - -local treatmentdata = fonts.treatments.data - -local function initialize(goodies) - local treatments = goodies.treatments - if treatments then - for name, data in next, treatments do - treatmentdata[name] = data -- always wins - end - end -end - -fontgoodies.register("treatments", initialize) - -local filenames = fontgoodies.filenames or allocate() -fontgoodies.filenames = filenames - -local filedata = filenames.data or allocate() -filenames.data = filedata - -local function initialize(goodies) -- design sizes are registered global - local fn = goodies.filenames - if fn then - for usedname, alternativenames in next, fn do - filedata[usedname] = alternativenames - end - end -end - -fontgoodies.register("filenames", initialize) - -function fontgoodies.filenames.resolve(name) - local fd = filedata[name] - if fd and findfile(name) == "" then - for i=1,#fd do - local fn = fd[i] - if findfile(fn) ~= "" then - return fn - end - end - else - -- no lookup, just use the regular mechanism - end - return name -end - -local designsizes = fontgoodies.designsizes or allocate() -fontgoodies.designsizes = designsizes - -local designdata = designsizes.data or allocate() -designsizes.data = designdata - -local function initialize(goodies) -- design sizes are registered global - local gd = goodies.designsizes - if gd then - for name, data in next, gd do - local ranges = { } - for size, file in next, data do - if size ~= "default" then - ranges[#ranges+1] = { texsp(size), file } -- also lower(file) - end - end - table.sort(ranges,function(a,b) return a[1] < b[1] end) - designdata[lower(name)] = { -- overloads, doesn't merge! - default = data.default, - ranges = ranges, - } - end - end -end - -fontgoodies.register("designsizes", initialize) - -function fontgoodies.designsizes.register(name,size,specification) - local d = designdata[name] - if not d then - d = { - ranges = { }, - default = nil, -- so we have no default set - } - designdata[name] = d - end - if size == "default" then - d.default = specification - else - if type(size) == "string" then - size = texsp(size) -- hm - end - local ranges = d.ranges - ranges[#ranges+1] = { size, specification } - end -end - -function fontgoodies.designsizes.filename(name,spec,size) -- returns nil of no match - local data = designdata[lower(name)] - if data then - if not spec or spec == "" or spec == "default" then - return data.default - elseif spec == "auto" then - local ranges = data.ranges - if ranges then - for i=1,#ranges do - local r = ranges[i] - if r[1] >= size then -- todo: rounding so maybe size - 100 - return r[2] - end - end - end - return data.default or (ranges and ranges[#ranges][2]) - end - end -end - --- The following file (husayni.lfg) is the experimental setup that we used --- for Idris font. For the moment we don't store this in the cache and quite --- probably these files sit in one of the paths: --- --- tex/context/fonts/goodies --- tex/fonts/goodies/context --- tex/fonts/data/foundry/collection --- --- see lfg files in distribution - --- interface - -implement { - name = "loadfontgoodies", - actions = fontgoodies.load, - arguments = "string", - overload = true, -- for now, permits new font loader -} - -implement { - name = "enablefontcolorschemes", - onlyonce = true, - actions = colorschemes.enable, - overload = true, -- for now, permits new font loader -} - --- weird place ... depends on math - -local function finalize(tfmdata,feature,value) - mathematics.overloaddimensions(tfmdata,tfmdata,value) -end - -registerotffeature { - name = "mathdimensions", - description = "manipulate math dimensions", - -- default = true, - manipulators = { - base = finalize, - node = finalize, - } -} - -local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) - -local function initialize(tfmdata) - if enabled and tfmdata.mathparameters then -- funny, cambria text has this - local goodies = tfmdata.goodies - if goodies then - local characters = tfmdata.characters - if characters[0x1D44E] then -- 119886 - -- we have at least an italic a - for i=1,#goodies do - local mathgoodies = goodies[i].mathematics - if mathgoodies then - local kerns = mathgoodies.kerns - if kerns then - for unicode, specification in next, kerns do - local chardata = characters[unicode] - if chardata and (not chardata.mathkerns or specification.force) then - chardata.mathkerns = specification - end - end - return - end - end - end - else - return -- no proper math font anyway - end - end - end -end - -registerotffeature { - name = "mathkerns", - description = "math kerns", - default = true, - initializers = { - base = initialize, - node = initialize, - } -} - --- kern hackery: --- --- yes : use goodies table --- auto : assume features to be set (often ccmp only) - -local function setkeepligatures(tfmdata) - if not tfmdata.properties.keptligatures then - local goodies = tfmdata.goodies - if goodies then - for i=1,#goodies do - local g = goodies[i] - local letterspacing = g.letterspacing - if letterspacing then - local keptligatures = letterspacing.keptligatures - if keptligatures then - local unicodes = tfmdata.resources.unicodes -- so we accept names - local hash = { } - for k, v in next, keptligatures do - local u = unicodes[k] - if u then - hash[u] = true - else - -- error: unknown name - end - end - tfmdata.properties.keptligatures = hash - end - end - end - end - end -end - -registerotffeature { - name = "keepligatures", - description = "keep ligatures in letterspacing", - initializers = { - base = setkeepligatures, - node = setkeepligatures, - } -} diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi index fd6f70d69..d13de4b3e 100644 --- a/tex/context/base/mkiv/font-lib.mkvi +++ b/tex/context/base/mkiv/font-lib.mkvi @@ -76,7 +76,11 @@ \registerctxluafile{font-vf} {1.001} \registerctxluafile{font-enh}{1.001} -\registerctxluafile{font-gds}{1.001} +%registerctxluafile{font-gds}{1.001} +\registerctxluafile{good-ini}{1.001} +\registerctxluafile{good-gen}{1.001} +\registerctxluafile{good-ctx}{1.001} +\registerctxluafile{good-mth}{1.001} \registerctxluafile{font-def}{1.001} \registerctxluafile{font-ctx}{1.001} % after def as it overloads diff --git a/tex/context/base/mkiv/font-otj.lua b/tex/context/base/mkiv/font-otj.lua index 0db30c646..d1408fd52 100644 --- a/tex/context/base/mkiv/font-otj.lua +++ b/tex/context/base/mkiv/font-otj.lua @@ -24,6 +24,8 @@ if not modules then modules = { } end modules ['font-otj'] = { -- The use_advance code is just a test and is meant for testing and manuals. There is no -- performance (or whatever) gain and using kerns is somewhat cleaner (at least for now). +-- Maybe: subtype fontkern when pure kerns. + if not nodes.properties then return end local next, rawget = next, rawget diff --git a/tex/context/base/mkiv/font-sel.lua b/tex/context/base/mkiv/font-sel.lua index 02dc9e686..4620319f5 100644 --- a/tex/context/base/mkiv/font-sel.lua +++ b/tex/context/base/mkiv/font-sel.lua @@ -70,7 +70,7 @@ local report_selectfont = logs.reporter("selectfont") local report_files = logs.reporter("selectfont","files") local report_features = logs.reporter("selectfont","features") local report_goodies = logs.reporter("selectfont","goodies") -local report_alternatives = logs.reporter("selectfont","alternatives") +----- report_alternatives = logs.reporter("selectfont","alternatives") local report_typescript = logs.reporter("selectfont","typescripts") defaults["rm"] = { features = { ["sc"] = "*,f:smallcaps" } } @@ -919,4 +919,4 @@ implement { name = "definefontfamilypreset", actions = selectfont.definefontfamilypreset, arguments = { "string", "string" } -} \ No newline at end of file +} diff --git a/tex/context/base/mkiv/good-ctx.lua b/tex/context/base/mkiv/good-ctx.lua new file mode 100644 index 000000000..4c8b9fcff --- /dev/null +++ b/tex/context/base/mkiv/good-ctx.lua @@ -0,0 +1,275 @@ +if not modules then modules = { } end modules ['good-ctx'] = { + version = 1.000, + 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" +} + +-- depends on ctx + +local type, next, tonumber = type, next, tonumber +local find, splitup = string.find, string.splitup + +local fonts = fonts +local nodes = nodes +local attributes = attributes + +----- trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) +----- report_goodies = logs.reporter("fonts","goodies") + +local allocate = utilities.storage.allocate +local setmetatableindex = table.setmetatableindex + +local implement = interfaces.implement + +local registerotffeature = fonts.handlers.otf.features.register +----- registerafmfeature = fonts.handlers.afm.features.register +----- registertfmfeature = fonts.handlers.tfm.features.register + +local fontgoodies = fonts.goodies or { } + +local glyph_code = nodes.nodecodes.glyph + +local nuts = nodes.nuts +local tonut = nuts.tonut +local getfont = nuts.getfont +local getchar = nuts.getchar +local getattr = nuts.getattr +local traverse_id = nuts.traverse_id + +-- colorschemes + +local colorschemes = fontgoodies.colorschemes or allocate { } +fontgoodies.colorschemes = colorschemes +colorschemes.data = colorschemes.data or { } + +local function setcolorscheme(tfmdata,scheme) + if type(scheme) == "string" then + local goodies = tfmdata.goodies + -- todo : check for already defined in shared + if goodies then + local what + for i=1,#goodies do + -- last one counts + local g = goodies[i] + what = g.colorschemes and g.colorschemes[scheme] or what + end + if type(what) == "table" then + -- this is font bound but we can share them if needed + -- just as we could hash the conversions (per font) + local hash = tfmdata.resources.unicodes + local reverse = { } + local characters = tfmdata.characters + for i=1,#what do + local w = what[i] + for j=1,#w do + local name = w[j] + if name == "*" then + -- inefficient but only used for tracing anyway + for _, unicode in next, hash do + reverse[unicode] = i + end + elseif type(name) == "number" then + reverse[name] = i + elseif find(name,":",1,true) then + local start, stop = splitup(name,":") + start = tonumber(start) + stop = tonumber(stop) + if start and stop then + -- limited usage: we only deal with non reassigned + -- maybe some day I'll also support the ones with a + -- tounicode in this range + for unicode=start,stop do + if characters[unicode] then + reverse[unicode] = i + end + end + end + else + local unicode = hash[name] + if unicode then + reverse[unicode] = i + end + end + end + end + tfmdata.properties.colorscheme = reverse + return + end + end + end + tfmdata.properties.colorscheme = false +end + +local fontproperties = fonts.hashes.properties + +local a_colorscheme = attributes.private('colorscheme') +local setnodecolor = nodes.tracers.colors.set + +-- function colorschemes.coloring(head) +-- local lastfont, lastscheme +-- local done = false +-- for n in traverse_id(glyph_code,tonut(head)) do +-- local a = getattr(n,a_colorscheme) +-- if a then +-- local f = getfont(n) +-- if f ~= lastfont then +-- lastscheme = fontproperties[f].colorscheme +-- lastfont = f +-- end +-- if lastscheme then +-- local sc = lastscheme[getchar(n)] +-- if sc then +-- done = true +-- setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow +-- end +-- end +-- end +-- end +-- return head, done +-- end + +-- seldom used, mostly in manuals, so non critical .. anyhow, somewhat faster: + +-- function colorschemes.coloring(head) +-- local lastfont = nil +-- local lastattr = nil +-- local lastscheme = nil +-- local lastprefix = nil +-- local done = nil +-- for n in traverse_id(glyph_code,tonut(head)) do +-- local a = getattr(n,a_colorscheme) +-- if a then +-- if a ~= lastattr then +-- lastattr = a +-- lastprefix = "colorscheme:" .. a .. ":" +-- end +-- local f = getfont(n) +-- if f ~= lastfont then +-- lastfont = f +-- lastscheme = fontproperties[f].colorscheme +-- end +-- if lastscheme then +-- local sc = lastscheme[getchar(n)] +-- if sc then +-- setnodecolor(n,lastprefix .. sc) -- slow +-- done = true +-- end +-- end +-- end +-- end +-- return head, done +-- end + +-- ok, in case we have hundreds of pages colored: + +local cache = { } -- this could be a weak table + +setmetatableindex(cache,function(t,a) + local v = { } + setmetatableindex(v,function(t,c) + local v = "colorscheme:" .. a .. ":" .. c + t[c] = v + return v + end) + t[a]= v + return v +end) + +function colorschemes.coloring(head) + local lastfont = nil + local lastattr = nil + local lastcache = nil + local lastscheme = nil + local done = nil + for n in traverse_id(glyph_code,tonut(head)) do + local a = getattr(n,a_colorscheme) + if a then + local f = getfont(n) + if f ~= lastfont then + lastfont = f + lastscheme = fontproperties[f].colorscheme + end + if a ~= lastattr then + lastattr = a + lastcache = cache[a] + end + if lastscheme then + local sc = lastscheme[getchar(n)] + if sc then + setnodecolor(n,lastcache[sc]) -- we could inline this one + done = true + end + end + end + end + return head, done +end + +function colorschemes.enable() + nodes.tasks.appendaction("processors","fonts","fonts.goodies.colorschemes.coloring") + function colorschemes.enable() end +end + +registerotffeature { + name = "colorscheme", + description = "goodie color scheme", + initializers = { + base = setcolorscheme, + node = setcolorscheme, + } +} + +-- kern hackery: +-- +-- yes : use goodies table +-- auto : assume features to be set (often ccmp only) + +local function setkeepligatures(tfmdata) + if not tfmdata.properties.keptligatures then + local goodies = tfmdata.goodies + if goodies then + for i=1,#goodies do + local g = goodies[i] + local letterspacing = g.letterspacing + if letterspacing then + local keptligatures = letterspacing.keptligatures + if keptligatures then + local unicodes = tfmdata.resources.unicodes -- so we accept names + local hash = { } + for k, v in next, keptligatures do + local u = unicodes[k] + if u then + hash[u] = true + else + -- error: unknown name + end + end + tfmdata.properties.keptligatures = hash + end + end + end + end + end +end + +registerotffeature { + name = "keepligatures", + description = "keep ligatures in letterspacing", + initializers = { + base = setkeepligatures, + node = setkeepligatures, + } +} + +if implement then + + implement { + name = "enablefontcolorschemes", + onlyonce = true, + actions = colorschemes.enable, + overload = true, -- for now, permits new font loader + } + +end diff --git a/tex/context/base/mkiv/good-gen.lua b/tex/context/base/mkiv/good-gen.lua new file mode 100644 index 000000000..cee6b3172 --- /dev/null +++ b/tex/context/base/mkiv/good-gen.lua @@ -0,0 +1,208 @@ +if not modules then modules = { } end modules ['good-gen'] = { + version = 1.000, + 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" +} + +-- depends on ctx + +local type, next = type, next +local lower = string.lower + +local fonts = fonts + +----- trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) +----- report_goodies = logs.reporter("fonts","goodies") + +local allocate = utilities.storage.allocate +local texsp = tex.sp +local fontgoodies = fonts.goodies or { } +local findfile = resolvers.findfile + + +local typefaces = fonts.typefaces or { } +fonts.typefaces = typefaces + +-- the following takes care of explicit file specifications +-- +-- files = { +-- name = "antykwapoltawskiego", +-- list = { +-- ["AntPoltLtCond-Regular.otf"] = { +-- -- name = "antykwapoltawskiego", +-- style = "regular", +-- weight = "light", +-- width = "condensed", +-- }, +-- }, +-- } + +-- files + +local function initialize(goodies) + local files = goodies.files + if files then + fonts.names.register(files) + end +end + +fontgoodies.register("files", initialize) + +-- some day we will have a define command and then we can also do some +-- proper tracing +-- +-- fonts.typefaces["antykwapoltawskiego-condensed"] = { +-- shortcut = "rm", +-- shape = "serif", +-- fontname = "antykwapoltawskiego", +-- normalweight = "light", +-- boldweight = "medium", +-- width = "condensed", +-- size = "default", +-- features = "default", +-- } + +local function initialize(goodies) + local typefaces = goodies.typefaces + if typefaces then + local ft = fonts.typefaces + for k, v in next, typefaces do + ft[k] = v + end + end +end + +fontgoodies.register("typefaces", initialize) + +local compositions = { } + +function fontgoodies.getcompositions(tfmdata) + return compositions[file.nameonly(tfmdata.properties.filename or "")] +end + +local function initialize(goodies) + local gc = goodies.compositions + if gc then + for k, v in next, gc do + compositions[k] = v + end + end +end + +fontgoodies.register("compositions", initialize) + +-- extra treatments (on top of defaults): \loadfontgoodies[mytreatments] + +local treatmentdata = fonts.treatments.data + +local function initialize(goodies) + local treatments = goodies.treatments + if treatments then + for name, data in next, treatments do + treatmentdata[name] = data -- always wins + end + end +end + +fontgoodies.register("treatments", initialize) + +local filenames = fontgoodies.filenames or allocate() +fontgoodies.filenames = filenames + +local filedata = filenames.data or allocate() +filenames.data = filedata + +local function initialize(goodies) -- design sizes are registered global + local fn = goodies.filenames + if fn then + for usedname, alternativenames in next, fn do + filedata[usedname] = alternativenames + end + end +end + +fontgoodies.register("filenames", initialize) + +function fontgoodies.filenames.resolve(name) + local fd = filedata[name] + if fd and findfile(name) == "" then + for i=1,#fd do + local fn = fd[i] + if findfile(fn) ~= "" then + return fn + end + end + else + -- no lookup, just use the regular mechanism + end + return name +end + +local designsizes = fontgoodies.designsizes or allocate() +fontgoodies.designsizes = designsizes + +local designdata = designsizes.data or allocate() +designsizes.data = designdata + +local function initialize(goodies) -- design sizes are registered global + local gd = goodies.designsizes + if gd then + for name, data in next, gd do + local ranges = { } + for size, file in next, data do + if size ~= "default" then + ranges[#ranges+1] = { texsp(size), file } -- also lower(file) + end + end + table.sort(ranges,function(a,b) return a[1] < b[1] end) + designdata[lower(name)] = { -- overloads, doesn't merge! + default = data.default, + ranges = ranges, + } + end + end +end + +fontgoodies.register("designsizes", initialize) + +function fontgoodies.designsizes.register(name,size,specification) + local d = designdata[name] + if not d then + d = { + ranges = { }, + default = nil, -- so we have no default set + } + designdata[name] = d + end + if size == "default" then + d.default = specification + else + if type(size) == "string" then + size = texsp(size) -- hm + end + local ranges = d.ranges + ranges[#ranges+1] = { size, specification } + end +end + +function fontgoodies.designsizes.filename(name,spec,size) -- returns nil of no match + local data = designdata[lower(name)] + if data then + if not spec or spec == "" or spec == "default" then + return data.default + elseif spec == "auto" then + local ranges = data.ranges + if ranges then + for i=1,#ranges do + local r = ranges[i] + if r[1] >= size then -- todo: rounding so maybe size - 100 + return r[2] + end + end + end + return data.default or (ranges and ranges[#ranges][2]) + end + end +end diff --git a/tex/context/base/mkiv/good-ini.lua b/tex/context/base/mkiv/good-ini.lua new file mode 100644 index 000000000..f11b0f004 --- /dev/null +++ b/tex/context/base/mkiv/good-ini.lua @@ -0,0 +1,349 @@ +if not modules then modules = { } end modules ['good-ini'] = { + version = 1.000, + 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" +} + +-- depends on ctx + +local type, next = type, next +local gmatch = string.gmatch + +local fonts = fonts + +local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) +local report_goodies = logs.reporter("fonts","goodies") + +local allocate = utilities.storage.allocate +local implement = interfaces.implement +local findfile = resolvers.findfile +local formatters = string.formatters + +local otf = fonts.handlers.otf +local afm = fonts.handlers.afm +local tfm = fonts.handlers.tfm + +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register +local registertfmfeature = tfm.features.register + +local addotffeature = otf.enhancers.addfeature + +local fontgoodies = fonts.goodies or { } +fonts.goodies = fontgoodies + +local data = fontgoodies.data or { } +fontgoodies.data = data -- no allocate as we want to see what is there + +local list = fontgoodies.list or { } +fontgoodies.list = list -- no allocate as we want to see what is there + +fontgoodies.suffixes = { "lfg", "lua" } -- lfg is context specific and should not be used elsewhere + +function fontgoodies.report(what,trace,goodies) + if trace_goodies or trace then + local whatever = goodies[what] + if whatever then + report_goodies("goodie %a found in %a",what,goodies.name) + end + end +end + +local function locate(filename) + local suffixes = fontgoodies.suffixes + for i=1,#suffixes do + local suffix = suffixes[i] + local fullname = findfile(file.addsuffix(filename,suffix)) + if fullname and fullname ~= "" then + return fullname + end + end +end + +local function loadgoodies(filename) -- maybe a merge is better + local goodies = data[filename] -- we assume no suffix is given + if goodies ~= nil then + -- found or tagged unfound + elseif type(filename) == "string" then + local fullname = locate(filename) + if not fullname or fullname == "" then + report_goodies("goodie file %a is not found (suffixes: % t)",filename,fontgoodies.suffixes) + data[filename] = false -- signal for not found + else + goodies = dofile(fullname) or false + if not goodies then + report_goodies("goodie file %a is invalid",fullname) + return nil + elseif trace_goodies then + report_goodies("goodie file %a is loaded",fullname) + end + goodies.name = goodies.name or "no name" + for name, fnc in next, list do + if trace_goodies then + report_goodies("handling goodie %a",name) + end + fnc(goodies) + end + goodies.initialized = true + data[filename] = goodies + end + end + return goodies +end + +function fontgoodies.register(name,fnc) -- will be a proper sequencer + list[name] = fnc +end + +fontgoodies.load = loadgoodies + +if implement then + + implement { + name = "loadfontgoodies", + actions = loadgoodies, + arguments = "string", + overload = true, -- for now, permits new font loader + } + +end + +-- register goodies file + +local function setgoodies(tfmdata,value) + local goodies = tfmdata.goodies + if not goodies then -- actually an error + goodies = { } + tfmdata.goodies = goodies + end + for filename in gmatch(value,"[^, ]+") do + -- we need to check for duplicates + local ok = loadgoodies(filename) + if ok then + if trace_goodies then + report_goodies("assigning goodie %a",filename) + end + goodies[#goodies+1] = ok + end + end +end + +-- featuresets + +local function flattenedfeatures(t,tt) + -- first set value dominates + local tt = tt or { } + for i=1,#t do + local ti = t[i] + if type(ti) == "table" then + flattenedfeatures(ti,tt) + elseif tt[ti] == nil then + tt[ti] = true + end + end + for k, v in next, t do + if type(k) ~= "number" then -- not tonumber(k) + if type(v) == "table" then + flattenedfeatures(v,tt) + elseif tt[k] == nil then + tt[k] = v + end + end + end + return tt +end + +-- fonts.features.flattened = flattenedfeatures + +local function prepare_features(goodies,name,set) + if set then + local ff = flattenedfeatures(set) + local fullname = goodies.name .. "::" .. name + local n, s = fonts.specifiers.presetcontext(fullname,"",ff) + goodies.featuresets[name] = s -- set + if trace_goodies then + report_goodies("feature set %a gets number %a and name %a",name,n,fullname) + end + return n + end +end + +fontgoodies.prepare_features = prepare_features + +local function initialize(goodies) + local featuresets = goodies.featuresets + if featuresets then + if trace_goodies then + report_goodies("checking featuresets in %a",goodies.name) + end + for name, set in next, featuresets do + prepare_features(goodies,name,set) + end + end +end + +fontgoodies.register("featureset",initialize) + +local function setfeatureset(tfmdata,set,features) + local goodies = tfmdata.goodies -- shared ? + if goodies then + local properties = tfmdata.properties + local what + for i=1,#goodies do + -- last one wins + local g = goodies[i] + what = g.featuresets and g.featuresets[set] or what + end + if what then + for feature, value in next, what do + if features[feature] == nil then + features[feature] = value + end + end + properties.mode = what.mode or properties.mode + end + end +end + +-- postprocessors (we could hash processor and share code) + +function fontgoodies.registerpostprocessor(tfmdata,f,prepend) + local postprocessors = tfmdata.postprocessors + if not postprocessors then + tfmdata.postprocessors = { f } + elseif prepend then + table.insert(postprocessors,f,1) + else + table.insert(postprocessors,f) + end +end + +local function setpostprocessor(tfmdata,processor) + local goodies = tfmdata.goodies + if goodies and type(processor) == "string" then + local found = { } + local asked = utilities.parsers.settings_to_array(processor) + for i=1,#goodies do + local g = goodies[i] + local p = g.postprocessors + if p then + for i=1,#asked do + local a = asked[i] + local f = p[a] + if type(f) == "function" then + found[a] = f + end + end + end + end + local postprocessors = tfmdata.postprocessors or { } + for i=1,#asked do + local a = asked[i] + local f = found[a] + if f then + postprocessors[#postprocessors+1] = f + end + end + if #postprocessors > 0 then + tfmdata.postprocessors = postprocessors + end + end +end + +local function setextrafeatures(tfmdata) + local goodies = tfmdata.goodies + if goodies then + for i=1,#goodies do + local g = goodies[i] + local f = g.features + if f then + for feature, specification in next, f do + addotffeature(tfmdata.shared.rawdata,feature,specification) + registerotffeature { + name = feature, + description = formatters["extra: %s"](feature) + } + end + end + end + end +end + +local function setextensions(tfmdata) + local goodies = tfmdata.goodies + if goodies then + for i=1,#goodies do + local g = goodies[i] + local e = g.extensions + if e then + local goodie = g.name or "unknown" + for i=1,#e do + local name = "extension-" .. i + -- report_goodies("adding extension %s from %s",name,goodie) + otf.enhancers.addfeature(tfmdata.shared.rawdata,name,e[i]) + end + end + end + end +end + +-- installation + +local goodies_specification = { + name = "goodies", + description = "goodies on top of built in features", + initializers = { + position = 1, + base = setgoodies, + node = setgoodies, + } +} + +registerotffeature(goodies_specification) +registerafmfeature(goodies_specification) +registertfmfeature(goodies_specification) + +-- maybe more of the following could be for type one too + +registerotffeature { + name = "extrafeatures", + description = "extra features", + default = true, + initializers = { + position = 2, + base = setextrafeatures, + node = setextrafeatures, + } +} + +registerotffeature { + name = "extensions", + description = "extensions to features", + default = true, + initializers = { + position = 2, + base = setextensions, + node = setextensions, + } +} + +registerotffeature { + name = "featureset", + description = "goodie feature set", + initializers = { + position = 3, + base = setfeatureset, + node = setfeatureset, + } +} + +registerotffeature { + name = "postprocessor", + description = "goodie postprocessor", + initializers = { + base = setpostprocessor, + node = setpostprocessor, + } +} diff --git a/tex/context/base/mkiv/good-mth.lua b/tex/context/base/mkiv/good-mth.lua new file mode 100644 index 000000000..7533a17c3 --- /dev/null +++ b/tex/context/base/mkiv/good-mth.lua @@ -0,0 +1,173 @@ +if not modules then modules = { } end modules ['good-mth'] = { + version = 1.000, + 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" +} + +local type, next = type, next + +local fonts = fonts + +local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) +local report_goodies = logs.reporter("fonts","goodies") + +local registerotffeature = fonts.handlers.otf.features.register +local fontgoodies = fonts.goodies or { } + +-- experiment, we have to load the definitions immediately as they precede +-- the definition so they need to be initialized in the typescript + +local function finalize(tfmdata,feature,value) + mathematics.overloaddimensions(tfmdata,tfmdata,value) +end + +registerotffeature { + name = "mathdimensions", + description = "manipulate math dimensions", + -- default = true, + manipulators = { + base = finalize, + node = finalize, + } +} + +local function initialize(goodies) + local mathgoodies = goodies.mathematics + if mathgoodies then + local virtuals = mathgoodies.virtuals + local mapfiles = mathgoodies.mapfiles + local maplines = mathgoodies.maplines + if virtuals then + for name, specification in next, virtuals do + -- beware, they are all constructed + mathematics.makefont(name,specification,goodies) + end + end + if mapfiles then + for i=1,#mapfiles do + fonts.mappings.loadfile(mapfiles[i]) -- todo: backend function + end + end + if maplines then + for i=1,#maplines do + fonts.mappings.loadline(maplines[i]) -- todo: backend function + end + end + end +end + +fontgoodies.register("mathematics", initialize) + +local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) + +local function initialize(tfmdata) + if enabled and tfmdata.mathparameters then -- funny, cambria text has this + local goodies = tfmdata.goodies + if goodies then + local characters = tfmdata.characters + if characters[0x1D44E] then -- 119886 + -- we have at least an italic a + for i=1,#goodies do + local mathgoodies = goodies[i].mathematics + if mathgoodies then + local kerns = mathgoodies.kerns + if kerns then + for unicode, specification in next, kerns do + local chardata = characters[unicode] + if chardata and (not chardata.mathkerns or specification.force) then + chardata.mathkerns = specification + end + end + return + end + end + end + else + return -- no proper math font anyway + end + end + end +end + +registerotffeature { + name = "mathkerns", + description = "math kerns", + default = true, + initializers = { + base = initialize, + node = initialize, + } +} + +-- math italics (not really needed) +-- +-- it would be nice to have a \noitalics\font option + +local function initialize(tfmdata) + local goodies = tfmdata.goodies + if goodies then + local shared = tfmdata.shared + for i=1,#goodies do + local mathgoodies = goodies[i].mathematics + if mathgoodies then + local mathitalics = mathgoodies.italics + if mathitalics then + local properties = tfmdata.properties + if properties.setitalics then + mathitalics = mathitalics[file.nameonly(properties.name)] or mathitalics + if mathitalics then + if trace_goodies then + report_goodies("loading mathitalics for font %a",properties.name) + end + local corrections = mathitalics.corrections + local defaultfactor = mathitalics.defaultfactor + -- properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change) + if corrections then + fontgoodies.registerpostprocessor(tfmdata, function(tfmdata) -- this is another tfmdata (a copy) + -- better make a helper so that we have less code being defined + local properties = tfmdata.properties + local parameters = tfmdata.parameters + local characters = tfmdata.characters + properties.mathitalic_defaultfactor = defaultfactor + properties.mathitalic_defaultvalue = defaultfactor * parameters.quad + if trace_goodies then + report_goodies("assigning mathitalics for font %a",properties.name) + end + local quad = parameters.quad + local hfactor = parameters.hfactor + for k, v in next, corrections do + local c = characters[k] + if c then + if v > -1 and v < 1 then + c.italic = v * quad + else + c.italic = v * hfactor + end + else + report_goodies("invalid mathitalics entry %U for font %a",k,properties.name) + end + end + end) + end + return -- maybe not as these can accumulate + end + end + end + end + end + end +end + +registerotffeature { + name = "mathitalics", + description = "additional math italic corrections", + -- default = true, + initializers = { + base = initialize, + node = initialize, + } +} + +-- fontgoodies.register("mathitalics", initialize) diff --git a/tex/context/base/mkiv/layo-ini.lua b/tex/context/base/mkiv/layo-ini.lua index d35d7ef69..bfe33595d 100644 --- a/tex/context/base/mkiv/layo-ini.lua +++ b/tex/context/base/mkiv/layo-ini.lua @@ -18,7 +18,7 @@ layouts = { local status = layouts.status -function status.leftorrightpagection(left,right) +function status.leftorrightpageaction(left,right) if left == nil then left, right = false, true end @@ -41,14 +41,14 @@ function status.leftorrightpagection(left,right) end end -function status.isleftpage() +function status.isleftpage(r) if not conditionals.layoutisdoublesided then return false elseif conditionals.layoutissinglesided then return false elseif texgetcount("pagenoshift") % 2 == 0 then - return texgetcount("realpageno") % 2 == 0 + return (r or texgetcount("realpageno")) % 2 == 0 else - return not texgetcount("realpageno") % 2 == 0 + return not (r or texgetcount("realpageno")) % 2 == 0 end end diff --git a/tex/context/base/mkiv/lxml-tab.lua b/tex/context/base/mkiv/lxml-tab.lua index 2925af5f9..3c386b7a3 100644 --- a/tex/context/base/mkiv/lxml-tab.lua +++ b/tex/context/base/mkiv/lxml-tab.lua @@ -1049,9 +1049,13 @@ local grammar_unparsed_text = P { "preamble", -- maybe we will add settings to result as well -local function _xmlconvert_(data, settings) +local function _xmlconvert_(data,settings) settings = settings or { } -- no_root strip_cm_and_dt given_entities parent_root error_handler preparexmlstate(settings) + local preprocessor = settings.preprocessor + if data and data ~= "" and type(preprocessor) == "function" then + data = preprocessor(data,settings) or data -- settings.currentresource + end if settings.parent_root then mt = getmetatable(settings.parent_root) else diff --git a/tex/context/base/mkiv/lxml-tex.lua b/tex/context/base/mkiv/lxml-tex.lua index 836286073..026cf520d 100644 --- a/tex/context/base/mkiv/lxml-tex.lua +++ b/tex/context/base/mkiv/lxml-tex.lua @@ -523,6 +523,8 @@ local function entityconverter(id,str,ent) -- todo: disable tex entities when ra return xmlprivatetoken(str) end +lxml.preprocessor = nil + local function lxmlconvert(id,data,compress,currentresource) local settings = { -- we're now roundtrip anyway unify_predefined_entities = false, -- is also default @@ -530,6 +532,7 @@ local function lxmlconvert(id,data,compress,currentresource) resolve_predefined_entities = true, -- is also default resolve_entities = function(str,ent) return entityconverter(id,str,ent) end, currentresource = tostring(currentresource or id), + preprocessor = lxml.preprocessor, } if compress and compress == variables.yes then settings.strip_cm_and_dt = true diff --git a/tex/context/base/mkiv/math-map.lua b/tex/context/base/mkiv/math-map.lua index 94dde4110..f3726cf72 100644 --- a/tex/context/base/mkiv/math-map.lua +++ b/tex/context/base/mkiv/math-map.lua @@ -164,6 +164,10 @@ local function toupper (n) local t = { } for i=0,25 do t[0x00041+i] = n+i end re local function tolower (n) local t = { } for i=0,25 do t[0x00061+i] = n+i end return t end local function tovector(t) return t end +-- how about 0x2A (ast) cq. 0x2217 +-- 0x2D (hyphen) cq. 0x2212 +-- 0x3A (colon) cq. 0x2236 + local regular_tf = { digits = todigit(0x00030), ucletters = toupper(0x00041), diff --git a/tex/context/base/mkiv/mult-def.lua b/tex/context/base/mkiv/mult-def.lua index 681144816..b74ced203 100644 --- a/tex/context/base/mkiv/mult-def.lua +++ b/tex/context/base/mkiv/mult-def.lua @@ -10565,6 +10565,10 @@ return { ["pe"]="توده", ["ro"]="stack", }, + ["stackname"]={ + ["en"]="stackname", + ["nl"]="stapelnaam", + }, ["start"]={ ["cs"]="start", ["de"]="start", diff --git a/tex/context/base/mkiv/page-mix.lua b/tex/context/base/mkiv/page-mix.lua index 5ff1abf09..1154a24f5 100644 --- a/tex/context/base/mkiv/page-mix.lua +++ b/tex/context/base/mkiv/page-mix.lua @@ -44,7 +44,6 @@ local vpack = nuts.vpack local freenode = nuts.free local concatnodes = nuts.concat local slidenodes = nuts.slide -- ok here as we mess with prev links intermediately -local findtail = nuts.tail local getfield = nuts.getfield local setfield = nuts.setfield @@ -63,8 +62,6 @@ local getbox = nuts.getbox local getskip = nuts.getskip local getattribute = nuts.getattribute -local texgetskip = tex.getskip - local theprop = nuts.theprop local nodepool = nuts.pool diff --git a/tex/context/base/mkiv/spac-ali.lua b/tex/context/base/mkiv/spac-ali.lua index a67a30133..dc206a2a2 100644 --- a/tex/context/base/mkiv/spac-ali.lua +++ b/tex/context/base/mkiv/spac-ali.lua @@ -115,7 +115,7 @@ local function handler(head,leftpage,realpageno) end function alignments.handler(head) - local leftpage = isleftpage(true,false) + local leftpage = isleftpage() local realpageno = texgetcount("realpageno") local head, done = handler(tonut(head),leftpage,realpageno) return tonode(head), done diff --git a/tex/context/base/mkiv/spac-ver.mkiv b/tex/context/base/mkiv/spac-ver.mkiv index 250e4e396..7fe41c6de 100644 --- a/tex/context/base/mkiv/spac-ver.mkiv +++ b/tex/context/base/mkiv/spac-ver.mkiv @@ -1256,14 +1256,14 @@ %D Keyword based strutting: -\letvalue{\??struts\v!yes }\setstrut % \setvalue{\??struts\v!yes }{\setstrut} -\letvalue{\??struts\v!auto }\setautostrut % \setvalue{\??struts\v!auto }{\setautostrut} -\letvalue{\??struts\v!no }\setnostrut % \setvalue{\??struts\v!no }{\setnostrut} -\letvalue{\??struts\v!cap }\setcapstrut % \setvalue{\??struts\v!cap }{\setcapstrut} -\letvalue{\??struts\v!fit }\setfontstrut % \setvalue{\??struts\v!fit }{\setfontstrut} -\letvalue{\??struts\v!line }\setstrut % \setvalue{\??struts\v!line }{\setstrut} -\letvalue{\??struts\s!default}\setstrut % \setvalue{\??struts\s!default}{\setstrut} -\letvalue{\??struts\empty }\setstrut % \setvalue{\??struts\empty }{\setstrut} +\letvalue{\??struts\v!yes }\setstrut +\letvalue{\??struts\v!auto }\setautostrut +\letvalue{\??struts\v!no }\setnostrut +\letvalue{\??struts\v!cap }\setcapstrut +\letvalue{\??struts\v!fit }\setfontstrut +\letvalue{\??struts\v!line }\setstrut +\letvalue{\??struts\s!default}\setstrut +\letvalue{\??struts\empty }\setstrut %D Handy: diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index d80b8b645..05b5087c8 100644 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index e5c33fd93..1d0b0b16e 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ diff --git a/tex/context/base/mkiv/trac-vis.lua b/tex/context/base/mkiv/trac-vis.lua index 080b72673..e37a31902 100644 --- a/tex/context/base/mkiv/trac-vis.lua +++ b/tex/context/base/mkiv/trac-vis.lua @@ -374,8 +374,11 @@ end local f_cache = { } local function fontkern(head,current) - local kern = getfield(current,"kern") + getfield(current,"expansion_factor") - local info = f_cache[kern] + local width = getfield(current,"kern") + local extra = getfield(current,"expansion_factor") + local kern = width + extra + local info = f_cache[kern] + -- report_visualize("fontkern: %p ex %p",width,extra) if info then -- print("hit fontkern") else diff --git a/tex/context/base/mkiv/typo-mar.lua b/tex/context/base/mkiv/typo-mar.lua index 2886c7887..fb03b23ea 100644 --- a/tex/context/base/mkiv/typo-mar.lua +++ b/tex/context/base/mkiv/typo-mar.lua @@ -9,70 +9,8 @@ if not modules then modules = { } end modules ['typo-mar'] = { -- todo: -- -- * autoleft/right depending on available space (or distance to margin) --- * stack across paragraphs, but that is messy and one should reconsider --- using margin data then as also vertical spacing kicks in -- * floating margin data, with close-to-call anchoring --- -- experiment (does not work, too much interference) --- --- local pdfprint = pdf.print --- local format = string.format --- --- anchors = anchors or { } --- --- local whatever = { } --- local factor = (7200/7227)/65536 --- --- function anchors.set(tag) --- whatever[tag] = { pdf.h, pdf.v } --- end --- --- function anchors.reset(tag) --- whatever[tag] = nil --- end --- --- function anchors.startmove(tag,how) -- save/restore nodes but they don't support moves --- local w = whatever[tag] --- if not w then --- -- error --- elseif how == "horizontal" or how == "h" then --- pdfprint("page",format(" q 1 0 0 1 %f 0 cm ", (w[1] - pdf.h) * factor)) --- elseif how == "vertical" or how == "v" then --- pdfprint("page",format(" q 1 0 0 1 0 %f cm ", (w[2] - pdf.v) * factor)) --- else --- pdfprint("page",format(" q 1 0 0 1 %f %f cm ", (w[1] - pdf.h) * factor, (w[2] - pdf.v) * factor)) --- end --- end --- --- function anchors.stopmove(tag) --- local w = whatever[tag] --- if not w then --- -- error --- else --- pdfprint("page"," Q ") --- end --- end --- --- local latelua = nodes.pool.latelua --- --- function anchors.node_set(tag) --- return latelua(formatters["anchors.set(%q)"](tag)) --- end --- --- function anchors.node_reset(tag) --- return latelua(formatters["anchors.reset(%q)"](tag)) --- end --- --- function anchors.node_start_move(tag,how) --- return latelua(formatters["anchors.startmove(%q,%q)](tag,how)) --- end --- --- function anchors.node_stop_move(tag) --- return latelua(formatters["anchors.stopmove(%q)"](tag)) --- end - --- so far - local format, validstring = string.format, string.valid local insert, remove, sortedkeys, fastcopy = table.insert, table.remove, table.sortedkeys, table.fastcopy local setmetatable, next = setmetatable, next @@ -138,6 +76,7 @@ local setattr = nuts.setattr local getsubtype = nuts.getsubtype local getlist = nuts.getlist local setlist = nuts.setlist +local setlink = nuts.setlink local getbox = nuts.getbox local takebox = nuts.takebox @@ -158,11 +97,12 @@ local userdefined_code = whatsitcodes.userdefined local nodepool = nuts.pool local new_usernumber = nodepool.usernumber +local new_hlist = nodepool.hlist local lateluafunction = nodepool.lateluafunction local texgetdimen = tex.getdimen ------ texgetcount = tex.getcount +local texgetcount = tex.getcount local texget = tex.get local isleftpage = layouts.status.isleftpage @@ -173,7 +113,6 @@ local addtoline = paragraphs.addtoline local moveinline = paragraphs.moveinline local calculatedelta = paragraphs.calculatedelta ------ a_specialcontent = attributes.private("specialcontent") local a_linenumber = attributes.private('linenumber') local inline_mark = nodepool.userids["margins.inline"] @@ -194,6 +133,7 @@ local nofsaved = 0 local nofstored = 0 local nofinlined = 0 local nofdelayed = 0 +local nofinjected = 0 local h_anchors = 0 local v_anchors = 0 @@ -257,7 +197,6 @@ end function margins.save(t) setmetatable(t,defaults) local content = takebox(t.number) - -- setattr(content,a_specialcontent,1) setprop(content,"specialcontent","margindata") local location = t.location local category = t.category @@ -392,7 +331,7 @@ local function realign(current,candidate) local atleft = true local hmove = 0 local delta = 0 - local leftpage = isleftpage(false,true) + local leftpage = isleftpage() local leftdelta = 0 local rightdelta = 0 local leftdistance = distance @@ -426,6 +365,8 @@ local function realign(current,candidate) if not leftpage then atleft = false end + else + -- v_left end local islocal = scope == v_local @@ -477,20 +418,23 @@ end -- table gets saved when the v_continue case is active. We use a special variant -- of position tracking, after all we only need the page number and vertical position. -local stacked = { } -- left/right keys depending on location +local validstacknames = { + [v_left ] = v_left , + [v_right] = v_right, + [v_inner] = v_inner, + [v_outer] = v_outer, +} + local cache = { } -local anchors = { } - -local function resetstacked(location) - if location then - local s = { } - stacked[location] = s - anchors[location] = false - return s - else - stacked = { } - anchors = { } - return stacked +local stacked = { [v_yes] = { }, [v_continue] = { } } +local anchors = { [v_yes] = { }, [v_continue] = { } } + +local function resetstacked(all) + stacked[v_yes] = { } + anchors[v_yes] = { } + if all then + stacked[v_continue] = { } + anchors[v_continue] = { } end end @@ -498,24 +442,45 @@ end local function sa(tag) -- maybe l/r keys ipv left/right keys local p = cache[tag] - if trace_marginstack then - report_margindata("updating anchor %a",tag) + if p then + if trace_marginstack then + report_margindata("updating anchor %a",tag) + end + p.p = true + p.y = true + setposition('md:v',tag,p) + cache[tag] = nil -- do this later, per page a cleanup end - p.p = true - p.y = true --- p.a = tag - setposition('md:v',tag,p) - cache[tag] = nil end local function setanchor(v_anchor) -- freezes the global here return lateluafunction(function() sa(v_anchor) end) end +local function aa(tag,n) -- maybe l/r keys ipv left/right keys + local p = jobpositions.gettobesaved('md:v',tag) + if p then + if trace_marginstack then + report_margindata("updating injected %a",tag) + end + local pages = p.pages + if not pages then + pages = { } + p.pages = pages + end + pages[n] = texgetcount("realpageno") + elseif trace_marginstack then + report_margindata("not updating injected %a",tag) + end +end + +local function addtoanchor(v_anchor,n) -- freezes the global here + return lateluafunction(function() aa(v_anchor,n) end) +end + local function markovershoot(current) -- todo: alleen als offset > line v_anchors = v_anchors + 1 cache[v_anchors] = fastcopy(stacked) --- cache[v_anchors] = stacked -- so we adapt the previous too local anchor = setanchor(v_anchors) -- local list = hpack_nodes(linked_nodes(anchor,getlist(current))) -- not ok, we need to retain width local list = hpack_nodes(linked_nodes(anchor,getlist(current)),getfield(current,"width"),"exactly")-- @@ -527,64 +492,6 @@ local function markovershoot(current) -- todo: alleen als offset > line setlist(current,list) end --- local function getovershoot(location) --- local p = getposition("md:v",v_anchors) --- local c = getposition("md:v",v_anchors+1) --- if p and c and p.p and p.p == c.p then --- local distance = p.y - c.y --- local offset = p[location] or 0 --- local overshoot = offset - distance --- if trace_marginstack then --- report_margindata("location %a, anchor %a, distance %p, offset %p, overshoot %p",location,v_anchors,distance,offset,overshoot) --- end --- if overshoot > 0 then --- return overshoot, offset, distance --- else --- return 0, offset, distance --- end --- elseif trace_marginstack then --- report_margindata("location %a, anchor %a, nothing to correct",location,v_anchors) --- end --- return 0, 0, 0 --- end - -local function getovershoot(location) - local c = getposition("md:v",v_anchors+1) - if c then - local p = false - local cp = c.p - for i=v_anchors,1,-1 do - local pi = getposition("md:v",i) - if pi.p == cp then - p = pi - else - break - end - end - if p then - local distance = p.y - c.y - local offset = p[location] or 0 - local overshoot = offset - distance - if trace_marginstack then - report_margindata("location %a, anchor %a, distance %p, offset %p, overshoot %p",location,v_anchors,distance,offset,overshoot) - end - if overshoot > 0 then - return overshoot, offset, distance - else - return 0, offset, distance - end - end - end - if trace_marginstack then - report_margindata("location %a, anchor %a, nothing to correct",location,v_anchors) - end - return 0, 0, 0 -end - -local function getanchor(location,anchor) - return getposition("md:v",anchor) -end - local function inject(parent,head,candidate) local box = candidate.box if not box then @@ -595,6 +502,7 @@ local function inject(parent,head,candidate) local depth = getfield(box,"depth") local shift = getfield(box,"shift") local stack = candidate.stack + local stackname = candidate.stackname local location = candidate.location local method = candidate.method local voffset = candidate.voffset @@ -604,8 +512,18 @@ local function inject(parent,head,candidate) local strutdepth = candidate.strutdepth local inline = candidate.inline local psubtype = getsubtype(parent) - local offset = stacked[location] + -- This stackname is experimental and therefore undocumented and basically + -- unsupported. It was introduced when we needed to support overlapping + -- of different anchors. + if not stackname or stackname == "" then + stackname = location + else + stackname = validstacknames[stackname] or location + end + local isstacked = stack == v_continue or stack == v_yes + local offset = stack and stack ~= "" and stacked[stack][stackname] local firstonstack = offset == false or offset == nil + nofinjected = nofinjected + 1 nofdelayed = nofdelayed + 1 -- yet untested baseline = tonumber(baseline) @@ -622,61 +540,79 @@ local function inject(parent,head,candidate) baseline = false -- strutheight -- actually a hack end end - candidate.width = width - candidate.hsize = getfield(parent,"width") -- we can also pass textwidth - candidate.psubtype = psubtype + candidate.width = width + candidate.hsize = getfield(parent,"width") -- we can also pass textwidth + candidate.psubtype = psubtype + candidate.stackname = stackname if trace_margindata then report_margindata("processing, index %s, height %p, depth %p, parent %a, method %a",candidate.n,height,depth,listcodes[psubtype],method) end - -- The next section handles the inline notes that are checked for overlap which - -- is somewhat tricky as that mechanism is mostly for paragraph boundnotes. - local stackedinline = inline and (stack == v_yes or stack == v_continue) - if stackedinline then + -- Overlap detection is somewhat complex because we have display and inline + -- notes mixed as well as inner and outer positioning. We do need to + -- handle it in the stream because we also keep lines together so we keep + -- track of page numbers of notes. + + if isstacked then firstonstack = true - if anchors[location] then - local a1 = getanchor(location,anchors[location]) - local a2 = getanchor(location,v_anchors+1) - if a1 and a2 and a1.p == a2.p then - local distance = a1.y - a2.y - if distance > offset then - -- report_margindata("location %s, no overlap, case 1",location) - elseif offset > 0 then - offset = offset - distance - firstonstack = false - -- report_margindata("location %s, overlap %a",location,offset) - -- else - -- report_margindata("location %s, no overlap, case 2",location) + local anchor = getposition("md:v") + if anchor and (location == v_inner or location == v_outer) then + local pages = anchor.pages + if pages then + local page = pages[nofinjected] + if page then + if isleftpage(page) then + stackname = location == v_inner and v_right or v_left + else + stackname = location == v_inner and v_left or v_right + end + candidate.stackname = stackname + offset = stack and stack ~= "" and stacked[stack][stackname] end - -- else - -- report_margindata("location %s, no overlap, case 3",location) end - -- else - -- report_margindata("location %s, no overlap, case 4",location) end - anchors[location] = v_anchors + 1 - end - -- end of special section - if firstonstack then - offset = 0 - else - -- offset = offset + height - end - if stack == v_yes then + local current = v_anchors + 1 + local previous = anchors[stack][stackname] + if trace_margindata then + report_margindata("anchor %i, offset so far %p",current,offset or 0) + end + local ap = anchor and anchor[previous] + local ac = anchor and anchor[current] + if not previous then + elseif previous == current then + firstonstack = false + elseif ap and ac and ap.p == ac.p then + local distance = ap.y - ac.y + if trace_margindata then + report_margindata("distance %p",distance) + end + if offset > distance then + -- we already overflow + offset = offset - distance + firstonstack = false + else + offset = 0 + end + else + -- what to do + end + anchors[v_yes] [stackname] = current + anchors[v_continue][stackname] = current + if firstonstack then + offset = 0 + end offset = offset + candidate.dy -- always shift = shift + offset - elseif stack == v_continue then - offset = offset + candidate.dy -- always + else if firstonstack then - offset = offset + getovershoot(location) + offset = 0 end - shift = shift + offset + offset = offset + candidate.dy -- always + shift = shift + offset end - -- -- -- -- Maybe we also need to patch offset when we apply methods, but how ... -- This needs a bit of playing as it depends on the stack setting of the -- following which we don't know yet ... so, consider stacking partially -- experimental. - -- -- -- if method == v_top then local delta = height - getfield(parent,"height") if trace_margindata then @@ -732,13 +668,19 @@ local function inject(parent,head,candidate) offset = offset + delta end setfield(box,"shift",shift) - setfield(box,"width",0) + setfield(box,"width",0) -- not needed when wrapped + -- + if isstacked then + setlink(box,addtoanchor(v_anchor,nofinjected)) + box = new_hlist(box) + -- set height / depth ? + end -- candidate.hook, candidate.node = addtoline(parent,box) -- setprop(box,"margindata",candidate) if trace_margindata then - report_margindata("injected, location %a, shift %p",location,shift) + report_margindata("injected, location %a, stack %a, shift %p",location,stackname,shift) end -- we need to add line etc to offset as well offset = offset + depth @@ -747,16 +689,17 @@ local function inject(parent,head,candidate) depth = offset, slack = candidate.bottomspace, -- todo: 'depth' => strutdepth lineheight = candidate.lineheight, -- only for tracing - stacked = stackedinline, + stacked = inline and isstacked, } offset = offset + height -- we need a restart ... when there is no overlap at all - stacked[location] = offset + stacked[v_yes] [stackname] = offset + stacked[v_continue][stackname] = offset -- todo: if no real depth then zero if trace_margindata then report_margindata("status, offset %s",offset) end - return getlist(parent), room, stackedinline or (stack == v_continue) + return getlist(parent), room, inline and isstacked or (stack == v_continue) end local function flushinline(parent,head) @@ -850,7 +793,6 @@ local function flushed(scope,parent) -- current is hlist setattr(parent,a_linenumber,a) end end - -- resetstacked() end return done, continue end @@ -890,9 +832,7 @@ local function handler(scope,head,group) report_margindata("flushing stage one, nothing done, %s left",nofstored) end end - -- if done then - resetstacked() -- why doesn't done work ok here? - -- end +resetstacked() return tonode(head), done else return head, false @@ -964,7 +904,6 @@ local function finalhandler(head) local id = getid(current) if id == hlist_code then -- only lines? local a = getprop(current,"margindata") --- if not a or a == 0 then if not a then finalhandler(getlist(current)) elseif realigned(current,a) then @@ -991,9 +930,11 @@ function margins.finalhandler(head) end head = tonut(head) local head, done = finalhandler(head) + resetstacked(true) head = tonode(head) return head, done else + resetstacked() return head, false end end @@ -1055,6 +996,7 @@ interfaces.implement { { "align" }, { "option" }, { "line", "integer" }, + { "stackname" }, { "stack" }, } } diff --git a/tex/context/base/mkiv/typo-mar.mkiv b/tex/context/base/mkiv/typo-mar.mkiv index 4c634a2d3..013974086 100644 --- a/tex/context/base/mkiv/typo-mar.mkiv +++ b/tex/context/base/mkiv/typo-mar.mkiv @@ -122,6 +122,7 @@ \c!scope=\v!global, \c!width=, % \c!stack=, + % \c!stackname=, % \c!option=, % \v!paragraph (follow shape) \c!line=0, \c!anchor=\v!text, @@ -131,8 +132,8 @@ \c!hoffset=\zeropoint, \c!voffset=\zeropoint] -\setupmarginframed % so, align should be set with the data command - [\c!strut=\v!yes, +\setupmarginframed % so, align should be set with the data command + [\c!strut=\v!yes, % so by default we scale the strut to the font ! \c!offset=\v!overlay, \c!fr!analyze=\v!yes, \c!frame=\v!off, @@ -303,6 +304,7 @@ % \fi align {\margindataparameter\c!align}% line \numexpr\margindataparameter\c!line\relax + stackname {\margindataparameter\c!stackname}% stack {\margindataparameter\c!stack}% \relax \else diff --git a/tex/context/interface/mkii/keys-cs.xml b/tex/context/interface/mkii/keys-cs.xml index ce8e41016..94f41a5a8 100644 --- a/tex/context/interface/mkii/keys-cs.xml +++ b/tex/context/interface/mkii/keys-cs.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-de.xml b/tex/context/interface/mkii/keys-de.xml index 5c7ecc651..edbba27c9 100644 --- a/tex/context/interface/mkii/keys-de.xml +++ b/tex/context/interface/mkii/keys-de.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-en.xml b/tex/context/interface/mkii/keys-en.xml index 621cbd763..9b0a7727a 100644 --- a/tex/context/interface/mkii/keys-en.xml +++ b/tex/context/interface/mkii/keys-en.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-fr.xml b/tex/context/interface/mkii/keys-fr.xml index 301f94628..dbc2955f5 100644 --- a/tex/context/interface/mkii/keys-fr.xml +++ b/tex/context/interface/mkii/keys-fr.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-it.xml b/tex/context/interface/mkii/keys-it.xml index 458acd5c1..dcd6e4502 100644 --- a/tex/context/interface/mkii/keys-it.xml +++ b/tex/context/interface/mkii/keys-it.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-nl.xml b/tex/context/interface/mkii/keys-nl.xml index 5e214c8bb..f2ce3629b 100644 --- a/tex/context/interface/mkii/keys-nl.xml +++ b/tex/context/interface/mkii/keys-nl.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-pe.xml b/tex/context/interface/mkii/keys-pe.xml index 1afb96c9a..e66ad4f09 100644 --- a/tex/context/interface/mkii/keys-pe.xml +++ b/tex/context/interface/mkii/keys-pe.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkii/keys-ro.xml b/tex/context/interface/mkii/keys-ro.xml index 8a7707a2d..2fe560325 100644 --- a/tex/context/interface/mkii/keys-ro.xml +++ b/tex/context/interface/mkii/keys-ro.xml @@ -1166,6 +1166,7 @@ + diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf index 39a841a19..0e4fe395e 100644 Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf index 1e326ed67..acb862767 100644 Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 4d1ef8322..19fb2482c 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 : 05/31/16 09:02:55 +-- merge date : 06/02/16 21:28:16 do -- begin closure to overcome local limits and interference -- cgit v1.2.3