summaryrefslogtreecommitdiff
path: root/tex/context/base/font-ext.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/font-ext.lua')
-rw-r--r--tex/context/base/font-ext.lua401
1 files changed, 207 insertions, 194 deletions
diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua
index 16a0008cc..acabdb465 100644
--- a/tex/context/base/font-ext.lua
+++ b/tex/context/base/font-ext.lua
@@ -20,95 +20,21 @@ local trace_expansion = false trackers.register("fonts.expansion", function(v
local report_expansions = logs.reporter("fonts","expansions")
local report_protrusions = logs.reporter("fonts","protrusions")
-commands = commands or { }
-
--[[ldx--
<p>When we implement functions that deal with features, most of them
will depend of the font format. Here we define the few that are kind
of neutral.</p>
--ldx]]--
-local fonts = fonts
-
-fonts.triggers = fonts.triggers or { }
-local triggers = fonts.triggers
-
-fonts.methods = fonts.methods or { }
-local methods = fonts.methods
-
-fonts.manipulators = fonts.manipulators or { }
-local manipulators = fonts.manipulators
-
-fonts.initializers = fonts.initializers or { }
-local initializers = fonts.initializers
-initializers.common = initializers.common or { }
-
-local otf = fonts.otf
-
---[[ldx--
-<p>This feature will remove inter-digit kerns.</p>
---ldx]]--
-
--- old code, no kerns set at this point, so this has to be done afterwards
---
--- table.insert(triggers,"equaldigits")
---
--- function initializers.common.equaldigits(tfmdata,value)
--- if value then
--- local chr = tfmdata.characters
--- for i = utfbyte('0'), utfbyte('9') do
--- local c = chr[i]
--- if c then
--- c.kerns = nil
--- end
--- end
--- end
--- end
+local fonts = fonts
+local handlers = fonts.handlers
+local otf = handlers.otf
---[[ldx--
-<p>This feature will give all glyphs an equal height and/or depth. Valid
-values are <type>none</type>, <type>height</type>, <type>depth</type> and
-<type>both</type>.</p>
---ldx]]--
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
--- old code, no dimensions set at this point, so this has to be done afterwards
---
--- table.insert(triggers,"lineheight")
---
--- function initializers.common.lineheight(tfmdata,value)
--- if value and type(value) == "string" then
--- if value == "none" then
--- for _,v in next, tfmdata.characters do
--- v.height, v.depth = 0, 0
--- end
--- else
--- local ascender, descender = tfmdata.ascender, tfmdata.descender
--- if ascender and descender then
--- local ht, dp = ascender or 0, descender or 0
--- if value == "height" then
--- dp = 0
--- elseif value == "depth" then
--- ht = 0
--- end
--- if ht > 0 then
--- if dp > 0 then
--- for _,v in next, tfmdata.characters do
--- v.height, v.depth = ht, dp
--- end
--- else
--- for _,v in next, tfmdata.characters do
--- v.height = ht
--- end
--- end
--- elseif dp > 0 then
--- for _,v in next, tfmdata.characters do
--- v.depth = dp
--- end
--- end
--- end
--- end
--- end
--- end
+local afmfeatures = fonts.constructors.newfeatures("afm")
+local registerafmfeature = afmfeatures.register
-- -- -- -- -- --
-- shared
@@ -116,11 +42,10 @@ values are <type>none</type>, <type>height</type>, <type>depth</type> and
local function get_class_and_vector(tfmdata,value,where) -- "expansions"
local g_where = tfmdata.goodies and tfmdata.goodies[where]
- local f_where = fonts[where]
+ local f_where = handlers[where]
local g_classes = g_where and g_where.classes
local f_classes = f_where and f_where.classes
local class = (g_classes and g_classes[value]) or (f_classes and f_classes[value])
---~ print(value,class,f_where,f_classes)
if class then
local class_vector = class.vector
local g_vectors = g_where and g_where.vectors
@@ -169,17 +94,26 @@ vectors['default'] = {
vectors['quality'] = vectors['default'] -- metatable ?
-function initializers.common.expansion(tfmdata,value)
+local function initializeexpansion(tfmdata,value)
if value then
local class, vector = get_class_and_vector(tfmdata,value,"expansions")
if class then
if vector then
- local stretch, shrink, step, factor = class.stretch or 0, class.shrink or 0, class.step or 0, class.factor or 1
+ local stretch = class.stretch or 0
+ local shrink = class.shrink or 0
+ local step = class.step or 0
+ local factor = class.factor or 1
if trace_expansion then
report_expansions("setting class %s, vector: %s, factor: %s, stretch: %s, shrink: %s, step: %s",
value,class.vector,factor,stretch,shrink,step)
end
- tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
+ tfmdata.parameters.expansion = {
+ stretch = 10 * stretch,
+ shrink = 10 * shrink,
+ step = 10 * step,
+ factor = factor,
+ auto = true,
+ }
local data = characters and characters.data
for i, chr in next, tfmdata.characters do
local v = vector[i]
@@ -211,13 +145,23 @@ function initializers.common.expansion(tfmdata,value)
end
end
-table.insert(manipulators,"expansion")
-
-initializers.base.otf.expansion = initializers.common.expansion
-initializers.node.otf.expansion = initializers.common.expansion
+registerotffeature {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
-initializers.base.afm.expansion = initializers.common.expansion
-initializers.node.afm.expansion = initializers.common.expansion
+registerafmfeature {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end)
@@ -374,10 +318,13 @@ classes['double'] = { -- for testing opbd
}
local function map_opbd_onto_protrusion(tfmdata,value,opbd)
- local characters, descriptions = tfmdata.characters, tfmdata.descriptions
- local otfdata = tfmdata.shared.otfdata
- local singles = otfdata.shared.featuredata.gpos_single
- local script, language = tfmdata.script, tfmdata.language
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ local rawdata = tfmdata.shared.rawdata
+ local lookuphash = rawdata.lookuphash
+ local script = properties.script
+ local language = properties.language
local done, factor, left, right = false, 1, 1, 1
local class = classes[value]
if class then
@@ -388,11 +335,11 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
factor = tonumber(value) or 1
end
if opbd ~= "right" then
- local validlookups, lookuplist = otf.collectlookups(otfdata,"lfbd",script,language)
+ local validlookups, lookuplist = otf.collectlookups(rawdata,"lfbd",script,language)
if validlookups then
for i=1,#lookuplist do
local lookup = lookuplist[i]
- local data = singles[lookup]
+ local data = lookuphash[lookup]
if data then
if trace_protrusion then
report_protrusions("setting left using lfbd lookup '%s'",lookup)
@@ -411,11 +358,11 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
end
end
if opbd ~= "left" then
- local validlookups, lookuplist = otf.collectlookups(otfdata,"rtbd",script,language)
+ local validlookups, lookuplist = otf.collectlookups(rawdata,"rtbd",script,language)
if validlookups then
for i=1,#lookuplist do
local lookup = lookuplist[i]
- local data = singles[lookup]
+ local data = lookuphash[lookup]
if data then
if trace_protrusion then
report_protrusions("setting right using rtbd lookup '%s'",lookup)
@@ -441,7 +388,7 @@ end
-- only has some kerns for digits. So, consider this feature not
-- supported till we have a proper test font.
-function initializers.common.protrusion(tfmdata,value)
+local function initializeprotrusion(tfmdata,value)
if value then
local opbd = tfmdata.shared.features.opbd
if opbd then
@@ -460,7 +407,12 @@ function initializers.common.protrusion(tfmdata,value)
end
local data = characters.data
local emwidth = tfmdata.parameters.quad
- tfmdata.auto_protrude = true
+ tfmdata.parameters.protrusion = {
+ factor = factor,
+ left = left,
+ right = right,
+ auto = true,
+ }
for i, chr in next, tfmdata.characters do
local v, pl, pr = vector[i], nil, nil
if v then
@@ -500,61 +452,80 @@ function initializers.common.protrusion(tfmdata,value)
end
end
-table.insert(manipulators,"protrusion")
-
-initializers.base.otf.protrusion = initializers.common.protrusion
-initializers.node.otf.protrusion = initializers.common.protrusion
+registerotffeature {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
-initializers.base.afm.protrusion = initializers.common.protrusion
-initializers.node.afm.protrusion = initializers.common.protrusion
+registerafmfeature {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end)
-- -- --
-function initializers.common.nostackmath(tfmdata,value)
- tfmdata.ignore_stack_math = value
+local function initializenostackmath(tfmdata,value)
+ tfmdata.properties.no_stackmath = value and true
end
-table.insert(manipulators,"nostackmath")
-
-initializers.base.otf.nostackmath = initializers.common.nostackmath
-initializers.node.otf.nostackmath = initializers.common.nostackmath
-
-table.insert(triggers,"itlc")
+registerotffeature {
+ name = "nostackmath",
+ description = "disable math stacking mechanism",
+ initializers = {
+ base = initializenostackmath,
+ node = initializenostackmath,
+ }
+}
-function initializers.common.itlc(tfmdata,value)
+local function initializeitlc(tfmdata,value)
if value then
-- the magic 40 and it formula come from Dohyun Kim
- local fontdata = tfmdata.shared.otfdata or tfmdata.shared.afmdata
- local metadata = fontdata and fontdata.metadata
- if metadata then
- local italicangle = metadata.italicangle
- if italicangle and italicangle ~= 0 then
- local uwidth = (metadata.uwidth or 40)/2
- for unicode, d in next, tfmdata.descriptions do
- local it = d.boundingbox[3] - d.width + uwidth
- if it ~= 0 then
- d.italic = it
- end
+ local parameters = tfmdata.parameters
+ local italicangle = parameters.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
end
- tfmdata.has_italic = true
end
+ tfmdata.properties.italic_correction = true
end
end
end
-initializers.base.otf.itlc = initializers.common.itlc
-initializers.node.otf.itlc = initializers.common.itlc
+registerotffeature {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
-initializers.base.afm.itlc = initializers.common.itlc
-initializers.node.afm.itlc = initializers.common.itlc
+registerafmfeature {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
-- slanting
-table.insert(triggers,"slant")
-
-function initializers.common.slant(tfmdata,value)
+local function initializeslant(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -563,18 +534,28 @@ function initializers.common.slant(tfmdata,value)
elseif value < -1 then
value = -1
end
- tfmdata.slant_factor = value
+ tfmdata.parameters.slant_factor = value
end
-initializers.base.otf.slant = initializers.common.slant
-initializers.node.otf.slant = initializers.common.slant
-
-initializers.base.afm.slant = initializers.common.slant
-initializers.node.afm.slant = initializers.common.slant
+registerotffeature {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
-table.insert(triggers,"extend")
+registerafmfeature {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
-function initializers.common.extend(tfmdata,value)
+local function initializeextend(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -583,58 +564,90 @@ function initializers.common.extend(tfmdata,value)
elseif value < -10 then
value = -10
end
- tfmdata.extend_factor = value
+ tfmdata.parameters.extend_factor = value
end
-initializers.base.otf.extend = initializers.common.extend
-initializers.node.otf.extend = initializers.common.extend
-
-initializers.base.afm.extend = initializers.common.extend
-initializers.node.afm.extend = initializers.common.extend
-
--- historic stuff, move from font-ota
-
-local delete_node = nodes.delete
-local fontdata = fonts.identifiers
-
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-
-fonts.strippables = fonts.strippables or { -- just a placeholder
- [0x200C] = true, -- zwnj
- [0x200D] = true, -- zwj
+registerotffeature {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
}
-local strippables = fonts.strippables
-
-local function processformatters(head,font)
- local how = fontdata[font].shared.features.formatters
- if how == nil or how == "strip" then -- nil when forced
- local current, done = head, false
- while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font then
- local char = current.char
- if strippables[char] then
- head, current = delete_node(head,current)
- done = true
- else
- current = current.next
- end
- else
- current = current.next
- end
- end
- return head, done
- else
- return head, false
- end
-end
-
-methods.node.otf.formatters = processformatters
-methods.base.otf.formatters = processformatters
-
-otf.tables.features['formatters'] = 'Hide Formatting Characters'
-
-otf.features.register("formatters")
+registerafmfeature {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
+}
-table.insert(manipulators,"formatters") -- at end
+-- -- historic stuff, move from font-ota (handled differently, typo-rep)
+--
+-- local delete_node = nodes.delete
+-- local fontdata = fonts.hashes.identifiers
+--
+-- local nodecodes = nodes.nodecodes
+-- local glyph_code = nodecodes.glyph
+--
+-- local strippables = allocate()
+-- fonts.strippables = strippables
+--
+-- strippables.joiners = table.tohash {
+-- 0x200C, -- zwnj
+-- 0x200D, -- zwj
+-- }
+--
+-- strippables.all = table.tohash {
+-- 0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
+-- 0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
+-- 0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
+-- 0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
+-- 0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
+-- 0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
+-- 0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
+-- 0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
+-- 0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
+-- 0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
+-- 0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
+-- 0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
+-- 0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
+-- }
+--
+-- strippables[true] = strippables.joiners
+--
+-- local function processformatters(head,font)
+-- local subset = fontdata[font].shared.features.formatters
+-- local vector = subset and strippables[subset]
+-- if vector then
+-- local current, done = head, false
+-- while current do
+-- if current.id == glyph_code and current.subtype<256 and current.font == font then
+-- local char = current.char
+-- if vector[char] then
+-- head, current = delete_node(head,current)
+-- done = true
+-- else
+-- current = current.next
+-- end
+-- else
+-- current = current.next
+-- end
+-- end
+-- return head, done
+-- else
+-- return head, false
+-- end
+-- end
+--
+-- registerotffeature {
+-- name = "formatters",
+-- description = "hide formatting characters",
+-- methods = {
+-- base = processformatters,
+-- node = processformatters,
+-- }
+-- }