diff options
Diffstat (limited to 'tex/context/base/mkiv/font-imp-spacekerns.lua')
-rw-r--r-- | tex/context/base/mkiv/font-imp-spacekerns.lua | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-imp-spacekerns.lua b/tex/context/base/mkiv/font-imp-spacekerns.lua new file mode 100644 index 000000000..0e2b0f9b0 --- /dev/null +++ b/tex/context/base/mkiv/font-imp-spacekerns.lua @@ -0,0 +1,258 @@ +if not modules then modules = { } end modules ['font-imp-spacekerns'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if not context then return end + +-- This is an experiment. See font-ots.lua for original implementation. + +local type, next = type, next +local insert, setmetatableindex = table.insert, table.setmetatableindex + +local fonts = fonts +local otf = fonts.handlers.otf +local fontdata = fonts.hashes.identifiers +local fontfeatures = fonts.hashes.features +local otffeatures = fonts.constructors.features.otf +local registerotffeature = otffeatures.register +local handlers = otf.handlers +local setspacekerns = nodes.injections.setspacekerns + +function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr) + local features = fontfeatures[font] + local enabled = features and features.spacekern + if enabled then + setspacekerns(font,sequence) -- called quite often, each glyphrun + end + return head, enabled +end + +local function hasspacekerns(data) + local resources = data.resources + local sequences = resources.sequences + local validgpos = resources.features.gpos + if validgpos and sequences then + for i=1,#sequences do + local sequence = sequences[i] + local steps = sequence.steps + if steps then -- and sequence.features[tag] then + local kind = sequence.type + if kind == "gpos_pair" then -- or kind == "gpos_single" then + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + local rules = step.rules + -- if rules then + -- -- not now: analyze (simple) rules + -- elseif not coverage then + -- -- nothing to do + -- elseif kind == "gpos_single" then + -- -- maybe a message that we ignore + -- elseif kind == "gpos_pair" then + if coverage and not rules then + local format = step.format + if format == "move" or format == "kern" then + local kerns = coverage[32] + if kerns then + return true + end + for k, v in next, coverage do + if v[32] then + return true + end + end + elseif format == "pair" then + local kerns = coverage[32] + if kerns then + for k, v in next, kerns do + local one = v[1] + if one and one ~= true then + return true + end + end + end + for k, v in next, coverage do + local kern = v[32] + if kern then + local one = kern[1] + if one and one ~= true then + return true + end + end + end + end + end + end + end + end + end + end + return false +end + +otf.readers.registerextender { + name = "spacekerns", + action = function(data) + data.properties.hasspacekerns = hasspacekerns(data) + end +} + +local function newdata(t,k) + local v = { + left = { }, + right = { }, + last = 0, + feat = nil, + } + t[k] = v + return v +end + +local function spaceinitializer(tfmdata,value) -- attr + local resources = tfmdata.resources + local spacekerns = resources and resources.spacekerns + if value and spacekerns == nil then + local rawdata = tfmdata.shared and tfmdata.shared.rawdata + local properties = rawdata.properties + if properties and properties.hasspacekerns then + local sequences = resources.sequences + local validgpos = resources.features.gpos + if validgpos and sequences then + local data = setmetatableindex(newdata) + for i=1,#sequences do + local sequence = sequences[i] + local steps = sequence.steps + if steps then + -- we don't support space kerns in other features + -- local kern = sequence.features[tag] + -- if kern then + for tag, kern in next, sequence.features do + + local d = data[tag] + local left = d.left + local right = d.right + local last = d.last + local feat = d.feat + + local kind = sequence.type + if kind == "gpos_pair" then -- or kind == "gpos_single" then + if feat then + for script, languages in next, kern do + local f = feat[script] + if f then + for l in next, languages do + f[l] = true + end + else + feat[script] = languages + end + end + else + feat = kern + d.feat = feat + end + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + local rules = step.rules + -- if rules then + -- -- not now: analyze (simple) rules + -- elseif not coverage then + -- -- nothing to do + -- elseif kind == "gpos_single" then + -- -- makes no sense in TeX + -- elseif kind == "gpos_pair" then + if coverage and not rules then + local format = step.format + if format == "move" or format == "kern" then + local kerns = coverage[32] + if kerns then + for k, v in next, kerns do + right[k] = v + end + end + for k, v in next, coverage do + local kern = v[32] + if kern then + left[k] = kern + end + end + elseif format == "pair" then + local kerns = coverage[32] + if kerns then + for k, v in next, kerns do + local one = v[1] + if one and one ~= true then + right[k] = one[3] + end + end + end + for k, v in next, coverage do + local kern = v[32] + if kern then + local one = kern[1] + if one and one ~= true then + left[k] = one[3] + end + end + end + end + end + end + last = i + end +d.last = last + end + end + end + + for tag, d in next, data do + local left = d.left + local right = d.right + left = next(left) and left or false + right = next(right) and right or false + if left or right then + + local last = d.last + local feat = d.feat + + if last > 0 then + local triggersequence = { + -- no steps, see (!!) + features = { [tag] = feat or { dflt = { dflt = true, } } }, + flags = noflags, + name = "trigger_space_kerns", + order = { tag }, + type = "trigger_space_kerns", + left = left, + right = right, + } + insert(sequences,last,triggersequence) + d.last = d.last + 1 + spacekerns = true + end + end + + end + end + end + if not spacekerns then + spacekerns = false + end + resources.spacekerns = spacekerns + end + return spacekerns +end + +registerotffeature { + name = "spacekern", + description = "space kern injection", + default = true, + initializers = { + node = spaceinitializer, + }, +} |