summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-imp-spacekerns.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-imp-spacekerns.lua')
-rw-r--r--tex/context/base/mkiv/font-imp-spacekerns.lua258
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,
+ },
+}