summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--luaotfload.dtx2
-rw-r--r--otfl-font-otc.lua334
2 files changed, 336 insertions, 0 deletions
diff --git a/luaotfload.dtx b/luaotfload.dtx
index ab8949c..d38ccd0 100644
--- a/luaotfload.dtx
+++ b/luaotfload.dtx
@@ -425,6 +425,7 @@ and the derived files
% \item |font-map.lua|
% \item |font-ota.lua|
% \item |font-otb.lua|
+% \item |font-otc.lua|
% \item |font-otf.lua|
% \item |font-oti.lua|
% \item |font-otn.lua|
@@ -580,6 +581,7 @@ require('otfl-font-otb.lua')
require('otfl-node-inj.lua')
require('otfl-font-otn.lua')
require('otfl-font-ota.lua')
+require('otfl-font-otc.lua')
require('otfl-fonts-lua.lua')
require('otfl-font-def.lua')
require('otfl-font-ltx.lua')
diff --git a/otfl-font-otc.lua b/otfl-font-otc.lua
new file mode 100644
index 0000000..ae463e7
--- /dev/null
+++ b/otfl-font-otc.lua
@@ -0,0 +1,334 @@
+if not modules then modules = { } end modules ['font-otc'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (context)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, insert = string.format, table.insert
+local type, next = type, next
+local lpegmatch = lpeg.match
+
+-- we assume that the other otf stuff is loaded already
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local report_otf = logs.reporter("fonts","otf loading")
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+local setmetatableindex = table.setmetatableindex
+
+-- In the userdata interface we can not longer tweak the loaded font as
+-- conveniently as before. For instance, instead of pushing extra data in
+-- in the table using the original structure, we now have to operate on
+-- the mkiv representation. And as the fontloader interface is modelled
+-- after fontforge we cannot change that one too much either.
+
+local types = {
+ substitution = "gsub_single",
+ ligature = "gsub_ligature",
+ alternate = "gsub_alternate",
+}
+
+setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key"
+
+local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
+local noflags = { }
+
+local function addfeature(data,feature,specifications)
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local lookups = resources.lookups
+ local gsubfeatures = resources.features.gsub
+ if gsubfeatures and gsubfeatures[feature] then
+ -- already present
+ else
+ local sequences = resources.sequences
+ local fontfeatures = resources.features
+ local unicodes = resources.unicodes
+ local lookuptypes = resources.lookuptypes
+ local splitter = lpeg.splitter(" ",unicodes)
+ local done = 0
+ local skip = 0
+ if not specifications[1] then
+ -- so we accept a one entry specification
+ specifications = { specifications }
+ end
+ -- subtables are tables themselves but we also accept flattened singular subtables
+ for s=1,#specifications do
+ local specification = specifications[s]
+ local valid = specification.valid
+ if not valid or valid(data,specification,feature) then
+ local initialize = specification.initialize
+ if initialize then
+ -- when false is returned we initialize only once
+ specification.initialize = initialize(specification) and initialize or nil
+ end
+ local askedfeatures = specification.features or everywhere
+ local subtables = specification.subtables or { specification.data } or { }
+ local featuretype = types[specification.type or "substitution"]
+ local featureflags = specification.flags or noflags
+ local added = false
+ local featurename = format("ctx_%s_%s",feature,s)
+ local st = { }
+ for t=1,#subtables do
+ local list = subtables[t]
+ local full = format("%s_%s",featurename,t)
+ st[t] = full
+ if featuretype == "gsub_ligature" then
+ lookuptypes[full] = "ligature"
+ for code, ligature in next, list do
+ local unicode = tonumber(code) or unicodes[code]
+ local description = descriptions[unicode]
+ if description then
+ local slookups = description.slookups
+ if type(ligature) == "string" then
+ ligature = { lpegmatch(splitter,ligature) }
+ end
+ local present = true
+ for i=1,#ligature do
+ if not descriptions[ligature[i]] then
+ present = false
+ break
+ end
+ end
+ if present then
+ if slookups then
+ slookups[full] = ligature
+ else
+ description.slookups = { [full] = ligature }
+ end
+ done, added = done + 1, true
+ else
+ skip = skip + 1
+ end
+ end
+ end
+ elseif featuretype == "gsub_single" then
+ lookuptypes[full] = "substitution"
+ for code, replacement in next, list do
+ local unicode = tonumber(code) or unicodes[code]
+ local description = descriptions[unicode]
+ if description then
+ local slookups = description.slookups
+ replacement = tonumber(replacement) or unicodes[replacement]
+ if descriptions[replacement] then
+ if slookups then
+ slookups[full] = replacement
+ else
+ description.slookups = { [full] = replacement }
+ end
+ done, added = done + 1, true
+ end
+ end
+ end
+ end
+ end
+ if added then
+ -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... }
+ for k, v in next, askedfeatures do
+ if v[1] then
+ askedfeatures[k] = table.tohash(v)
+ end
+ end
+ sequences[#sequences+1] = {
+ chain = 0,
+ features = { [feature] = askedfeatures },
+ flags = featureflags,
+ name = featurename,
+ subtables = st,
+ type = featuretype,
+ }
+ -- register in metadata (merge as there can be a few)
+ if not gsubfeatures then
+ gsubfeatures = { }
+ fontfeatures.gsub = gsubfeatures
+ end
+ local k = gsubfeatures[feature]
+ if not k then
+ k = { }
+ gsubfeatures[feature] = k
+ end
+ for script, languages in next, askedfeatures do
+ local kk = k[script]
+ if not kk then
+ kk = { }
+ k[script] = kk
+ end
+ for language, value in next, languages do
+ kk[language] = value
+ end
+ end
+ end
+ end
+ end
+ if trace_loading then
+ report_otf("enhance: registering feature '%s', %s glyphs affected, %s glyphs skipped",feature,done,skip)
+ end
+ end
+end
+
+otf.enhancers.addfeature = addfeature
+
+local extrafeatures = { }
+
+function otf.addfeature(name,specification)
+ extrafeatures[name] = specification
+end
+
+local function enhance(data,filename,raw)
+ for feature, specification in next, extrafeatures do
+ addfeature(data,feature,specification)
+ end
+end
+
+otf.enhancers.register("check extra features",enhance)
+
+-- tlig --
+
+local tlig = {
+ endash = "hyphen hyphen",
+ emdash = "hyphen hyphen hyphen",
+ -- quotedblleft = "quoteleft quoteleft",
+ -- quotedblright = "quoteright quoteright",
+ -- quotedblleft = "grave grave",
+ -- quotedblright = "quotesingle quotesingle",
+ -- quotedblbase = "comma comma",
+}
+
+local tlig_specification = {
+ type = "ligature",
+ features = everywhere,
+ data = tlig,
+ flags = noflags,
+}
+
+otf.addfeature("tlig",tlig_specification)
+
+registerotffeature {
+ name = 'tlig',
+ description = 'tex ligatures',
+}
+
+-- trep
+
+local trep = {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+}
+
+local trep_specification = {
+ type = "substitution",
+ features = everywhere,
+ data = trep,
+ flags = noflags,
+}
+
+otf.addfeature("trep",trep_specification)
+
+registerotffeature {
+ name = 'trep',
+ description = 'tex replacements',
+}
+
+-- tcom
+
+if characters.combined then
+
+ local tcom = { }
+
+ local function initialize()
+ characters.initialize()
+ for first, seconds in next, characters.combined do
+ for second, combination in next, seconds do
+ tcom[combination] = { first, second }
+ end
+ end
+ -- return false
+ end
+
+ local tcom_specification = {
+ type = "ligature",
+ features = everywhere,
+ data = tcom,
+ flags = noflags,
+ initialize = initialize,
+ }
+
+ otf.addfeature("tcom",tcom_specification)
+
+ registerotffeature {
+ name = 'tcom',
+ description = 'tex combinations',
+ }
+
+end
+
+-- anum
+
+local anum_arabic = {
+ [0x0030] = 0x0660,
+ [0x0031] = 0x0661,
+ [0x0032] = 0x0662,
+ [0x0033] = 0x0663,
+ [0x0034] = 0x0664,
+ [0x0035] = 0x0665,
+ [0x0036] = 0x0666,
+ [0x0037] = 0x0667,
+ [0x0038] = 0x0668,
+ [0x0039] = 0x0669,
+}
+
+local anum_persian = {
+ [0x0030] = 0x06F0,
+ [0x0031] = 0x06F1,
+ [0x0032] = 0x06F2,
+ [0x0033] = 0x06F3,
+ [0x0034] = 0x06F4,
+ [0x0035] = 0x06F5,
+ [0x0036] = 0x06F6,
+ [0x0037] = 0x06F7,
+ [0x0038] = 0x06F8,
+ [0x0039] = 0x06F9,
+}
+
+local function valid(data)
+ local features = data.resources.features
+ if features then
+ for k, v in next, features do
+ for k, v in next, v do
+ if v.arab then
+ return true
+ end
+ end
+ end
+ end
+end
+
+local anum_specification = {
+ {
+ type = "substitution",
+ features = { arab = { URD = true, dflt = true } },
+ data = anum_arabic,
+ flags = noflags, -- { },
+ valid = valid,
+ },
+ {
+ type = "substitution",
+ features = { arab = { URD = true } },
+ data = anum_persian,
+ flags = noflags, -- { },
+ valid = valid,
+ },
+}
+
+otf.addfeature("anum",anum_specification) -- todo: only when there is already an arab script feature
+
+registerotffeature {
+ name = 'anum',
+ description = 'arabic digits',
+}