diff options
author | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
commit | 13ec4b540e0d46c97fd7b089e0b7413da81e0a9f (patch) | |
tree | bebfa563a17c06b3bd3bf8f6f4ba6d025e00d107 /tex/context/base/font-gds.lua | |
parent | 69ad13650cda027526271179e95b5294694143a1 (diff) | |
download | context-13ec4b540e0d46c97fd7b089e0b7413da81e0a9f.tar.gz |
beta 2013.05.19 19:27
Diffstat (limited to 'tex/context/base/font-gds.lua')
-rw-r--r-- | tex/context/base/font-gds.lua | 1504 |
1 files changed, 752 insertions, 752 deletions
diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua index 6332f40b0..4eb57bfa4 100644 --- a/tex/context/base/font-gds.lua +++ b/tex/context/base/font-gds.lua @@ -1,752 +1,752 @@ -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, format, lower, find, splitup = string.gmatch, string.format, string.lower, string.find, string.splitup -local texsp = tex.sp - -local fonts, nodes, attributes, node = fonts, nodes, attributes, 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 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 - -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 - 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,tfmdata) - local featuresets = goodies.featuresets - local goodiesname = goodies.name - 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,":") 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 fontdata = fonts.hashes.identifiers -local setnodecolor = nodes.tracers.colors.set -local traverse_id = node.traverse_id -local a_colorscheme = attributes.private('colorscheme') -local glyph = node.id("glyph") - -function colorschemes.coloring(head) - local lastfont, lastscheme - local done = false - for n in traverse_id(glyph,head) do - local a = n[a_colorscheme] - if a then - local f = n.font - if f ~= lastfont then - lastscheme, lastfont = fontdata[f].properties.colorscheme, f - end - if lastscheme then - local sc = lastscheme[n.char] - if sc then - done = true - setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow - 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 = format("extra: %s",feature) - } - end - end - end - end -end - --- installation (collected to keep the overview) -- also for type 1 - -registerotffeature { - name = "goodies", - description = "goodies on top of built in features", - initializers = { - position = 1, - base = setgoodies, - node = setgoodies, - } -} - -registerotffeature { - name = "extrafeatures", - description = "extra features", - default = true, - initializers = { - position = 2, - base = setextrafeatures, - node = setextrafeatures, - } -} - -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, - } -} - --- afm - -registerafmfeature { - name = "goodies", - description = "goodies on top of built in features", - initializers = { - position = 1, - base = setgoodies, - node = setgoodies, - } -} - --- tfm - -registertfmfeature { - name = "goodies", - description = "goodies on top of built in features", - initializers = { - position = 1, - base = setgoodies, - node = setgoodies, - } -} - --- 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 - --- 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 - local mathitalics = mathgoodies and mathgoodies.italics - if mathitalics then - local properties = tfmdata.properties - 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 - local disableengine = mathitalics.disableengine - properties.hasitalics = true - properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change) - if properties.mathitalics == nil then - properties.mathitalics = disableengine - end - if corrections then - -- As we want to set italic_correction (the context one) we need a - -- postprocessor instead of messing with the (unscaled) descriptions. - 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.hasitalics = true - properties.mathitalic_defaultfactor = defaultfactor - properties.mathitalic_defaultvalue = defaultfactor * parameters.quad - if properties.mathitalics == nil then - properties.mathitalics = disableengine - end - if trace_goodies then - report_goodies("assigning mathitalics for font %a",properties.name) - end - local mathitalics = properties.mathitalics - local quad = parameters.quad - local hfactor = parameters.hfactor - for k, v in next, corrections do - local c = characters[k] - if v > -1 and v < 1 then - v = v * quad - else - v = v * hfactor - end - c.italic_correction = v -- for context - if mathitalics then - c.italic = v -- for tex - else - c.italic = nil - end - end - end) - end - return -- maybe not as these can accumulate - 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) - end - local ranges = d.ranges - ranges[#ranges+1] = { size, specification } - end -end - -function fontgoodies.designsizes.filename(name,spec,size) -- returns nil of no match - if spec and spec ~= "" then - local data = designdata[lower(name)] - if data then - if 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 -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 - -commands.loadfontgoodies = fontgoodies.load -commands.enablefontcolorschemes = colorschemes.enable - --- 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, - } -} +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, format, lower, find, splitup = string.gmatch, string.format, string.lower, string.find, string.splitup
+local texsp = tex.sp
+
+local fonts, nodes, attributes, node = fonts, nodes, attributes, 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 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
+
+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
+ 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,tfmdata)
+ local featuresets = goodies.featuresets
+ local goodiesname = goodies.name
+ 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,":") 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 fontdata = fonts.hashes.identifiers
+local setnodecolor = nodes.tracers.colors.set
+local traverse_id = node.traverse_id
+local a_colorscheme = attributes.private('colorscheme')
+local glyph = node.id("glyph")
+
+function colorschemes.coloring(head)
+ local lastfont, lastscheme
+ local done = false
+ for n in traverse_id(glyph,head) do
+ local a = n[a_colorscheme]
+ if a then
+ local f = n.font
+ if f ~= lastfont then
+ lastscheme, lastfont = fontdata[f].properties.colorscheme, f
+ end
+ if lastscheme then
+ local sc = lastscheme[n.char]
+ if sc then
+ done = true
+ setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow
+ 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 = format("extra: %s",feature)
+ }
+ end
+ end
+ end
+ end
+end
+
+-- installation (collected to keep the overview) -- also for type 1
+
+registerotffeature {
+ name = "goodies",
+ description = "goodies on top of built in features",
+ initializers = {
+ position = 1,
+ base = setgoodies,
+ node = setgoodies,
+ }
+}
+
+registerotffeature {
+ name = "extrafeatures",
+ description = "extra features",
+ default = true,
+ initializers = {
+ position = 2,
+ base = setextrafeatures,
+ node = setextrafeatures,
+ }
+}
+
+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,
+ }
+}
+
+-- afm
+
+registerafmfeature {
+ name = "goodies",
+ description = "goodies on top of built in features",
+ initializers = {
+ position = 1,
+ base = setgoodies,
+ node = setgoodies,
+ }
+}
+
+-- tfm
+
+registertfmfeature {
+ name = "goodies",
+ description = "goodies on top of built in features",
+ initializers = {
+ position = 1,
+ base = setgoodies,
+ node = setgoodies,
+ }
+}
+
+-- 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
+
+-- 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
+ local mathitalics = mathgoodies and mathgoodies.italics
+ if mathitalics then
+ local properties = tfmdata.properties
+ 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
+ local disableengine = mathitalics.disableengine
+ properties.hasitalics = true
+ properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change)
+ if properties.mathitalics == nil then
+ properties.mathitalics = disableengine
+ end
+ if corrections then
+ -- As we want to set italic_correction (the context one) we need a
+ -- postprocessor instead of messing with the (unscaled) descriptions.
+ 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.hasitalics = true
+ properties.mathitalic_defaultfactor = defaultfactor
+ properties.mathitalic_defaultvalue = defaultfactor * parameters.quad
+ if properties.mathitalics == nil then
+ properties.mathitalics = disableengine
+ end
+ if trace_goodies then
+ report_goodies("assigning mathitalics for font %a",properties.name)
+ end
+ local mathitalics = properties.mathitalics
+ local quad = parameters.quad
+ local hfactor = parameters.hfactor
+ for k, v in next, corrections do
+ local c = characters[k]
+ if v > -1 and v < 1 then
+ v = v * quad
+ else
+ v = v * hfactor
+ end
+ c.italic_correction = v -- for context
+ if mathitalics then
+ c.italic = v -- for tex
+ else
+ c.italic = nil
+ end
+ end
+ end)
+ end
+ return -- maybe not as these can accumulate
+ 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)
+ end
+ local ranges = d.ranges
+ ranges[#ranges+1] = { size, specification }
+ end
+end
+
+function fontgoodies.designsizes.filename(name,spec,size) -- returns nil of no match
+ if spec and spec ~= "" then
+ local data = designdata[lower(name)]
+ if data then
+ if 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
+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
+
+commands.loadfontgoodies = fontgoodies.load
+commands.enablefontcolorschemes = colorschemes.enable
+
+-- 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,
+ }
+}
|