diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ext.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-ext.lua | 468 |
1 files changed, 249 insertions, 219 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ext.lua b/Master/texmf-dist/tex/context/base/font-ext.lua index 05bdaf2fc3a..4ea9cf3caa0 100644 --- a/Master/texmf-dist/tex/context/base/font-ext.lua +++ b/Master/texmf-dist/tex/context/base/font-ext.lua @@ -10,11 +10,15 @@ local utf = unicode.utf8 local next, type, byte = next, type, string.byte local gmatch, concat = string.gmatch, table.concat local utfchar = utf.char +local getparameters = utilities.parsers.getparameters + +local allocate = utilities.storage.allocate local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) -commands = commands or { } +local report_expansions = logs.reporter("fonts","expansions") +local report_protrusions = logs.reporter("fonts","protrusions") --[[ldx-- <p>When we implement functions that deal with features, most of them @@ -22,74 +26,13 @@ will depend of the font format. Here we define the few that are kind of neutral.</p> --ldx]]-- -fonts.triggers = fonts.triggers or { } -fonts.initializers = fonts.initializers or { } -fonts.methods = fonts.methods or { } -fonts.initializers.common = fonts.initializers.common or { } - -local initializers = fonts.initializers -local methods = fonts.methods - ---[[ldx-- -<p>This feature will remove inter-digit kerns.</p> ---ldx]]-- - -table.insert(fonts.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 ---[[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 -table.insert(fonts.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 @@ -99,11 +42,13 @@ 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 g_classes = g_where and g_where.classes - local class = g_where and g_where[value] or f_where.classes[value] + local f_classes = f_where and f_where.classes + local class = (g_classes and g_classes[value]) or (f_classes and f_classes[value]) if class then local class_vector = class.vector local g_vectors = g_where and g_where.vectors - local vector = g_vectors and g_vectors[class_vector] or f_where.vectors[class_vector] + local f_vectors = f_where and f_where.vectors + local vector = (g_vectors and g_vectors[class_vector]) or (f_vectors and f_vectors[class_vector]) return class, vector end end @@ -112,20 +57,21 @@ end -- expansion (hz) -- -- -- -- -- -- -fonts.expansions = fonts.expansions or { } -fonts.expansions.classes = fonts.expansions.classes or { } -fonts.expansions.vectors = fonts.expansions.vectors or { } +fonts.expansions = allocate() +local expansions = fonts.expansions -local expansions = fonts.expansions -local classes = fonts.expansions.classes -local vectors = fonts.expansions.vectors +expansions.classes = allocate() +local classes = expansions.classes + +expansions.vectors = allocate() +local vectors = expansions.vectors -- beware, pdftex itself uses percentages * 10 classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 } function commands.setupfontexpansion(class,settings) - aux.getparameters(classes,class,'preset',settings) + getparameters(classes,class,'preset',settings) end classes['quality'] = { @@ -146,31 +92,26 @@ vectors['default'] = { vectors['quality'] = vectors['default'] -- metatable ? ---~ function table.locator(...) ---~ local k = { ... } ---~ return function(t) ---~ for i=1,#k do ---~ t = t[k[i]] ---~ if not k then ---~ return false ---~ end ---~ end ---~ return t ---~ end ---~ end - ---~ local locate = table.locator { "goodies", "expansions" } - -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 - logs.report("fonts","set expansion class %s, vector: %s, factor: %s, stretch: %s, shrink: %s, step: %s",value,class_vector,factor,stretch,shrink,step) + 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] @@ -194,42 +135,55 @@ function initializers.common.expansion(tfmdata,value) end end elseif trace_expansion then - logs.report("fonts","unknown expansion vector '%s' in class '%s",class_vector,value) + report_expansions("unknown vector '%s' in class '%s",class.vector,value) end elseif trace_expansion then - logs.report("fonts","unknown expansion class '%s'",value) + report_expansions("unknown class '%s'",value) end end end -table.insert(fonts.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) +local report_opbd = logs.reporter("fonts","otf opbd") + -- -- -- -- -- -- -- protrusion -- -- -- -- -- -- -fonts.protrusions = fonts.protrusions or { } -fonts.protrusions.classes = fonts.protrusions.classes or { } -fonts.protrusions.vectors = fonts.protrusions.vectors or { } +fonts.protrusions = allocate() +local protrusions = fonts.protrusions + +protrusions.classes = allocate() +protrusions.vectors = allocate() -local protrusions = fonts.protrusions -local classes = fonts.protrusions.classes -local vectors = fonts.protrusions.vectors +local classes = protrusions.classes +local vectors = protrusions.vectors -- the values need to be revisioned classes.preset = { factor = 1, left = 1, right = 1 } function commands.setupfontprotrusion(class,settings) - aux.getparameters(classes,class,'preset',settings) + getparameters(classes,class,'preset',settings) end classes['pure'] = { @@ -252,6 +206,7 @@ vectors['pure'] = { [0x003A] = { 0, 1 }, -- colon [0x003B] = { 0, 1 }, -- semicolon [0x002D] = { 0, 1 }, -- hyphen + [0x00AD] = { 0, 1 }, -- also hyphen [0x2013] = { 0, 0.50 }, -- endash [0x2014] = { 0, 0.33 }, -- emdash [0x3001] = { 0, 1 }, -- ideographic comma 、 @@ -277,6 +232,7 @@ vectors['punctuation'] = { [0x003A] = { 0, 0.50 }, -- colon [0x003B] = { 0, 0.50 }, -- semicolon [0x002D] = { 0, 0.70 }, -- hyphen + [0x00AD] = { 0, 0.70 }, -- also hyphen [0x2013] = { 0, 0.30 }, -- endash [0x2014] = { 0, 0.20 }, -- emdash [0x060C] = { 0, 0.70 }, -- arabic comma @@ -325,7 +281,7 @@ vectors['alpha'] = { } -vectors['quality'] = table.merge( {}, +vectors['quality'] = table.merged( vectors['punctuation'], vectors['alpha'] ) @@ -360,10 +316,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 @@ -374,21 +333,21 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) factor = tonumber(value) or 1 end if opbd ~= "right" then - local validlookups, lookuplist = fonts.otf.collect_lookups(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 - logs.report("fonts","set left protrusion using lfbd lookup '%s'",lookup) + report_protrusions("setting left using lfbd lookup '%s'",lookup) end for k, v in next, data do -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same local p = - (v[1] / 1000) * factor * left characters[k].left_protruding = p if trace_protrusion then - logs.report("opbd","lfbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) + report_protrusions("lfbd -> %s -> U+%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) end end done = true @@ -397,21 +356,21 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) end end if opbd ~= "left" then - local validlookups, lookuplist = fonts.otf.collect_lookups(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 - logs.report("fonts","set right protrusion using rtbd lookup '%s'",lookup) + report_protrusions("setting right using rtbd lookup '%s'",lookup) end for k, v in next, data do -- local p = v[3] / descriptions[k].width -- or 3 local p = (v[1] / 1000) * factor * right characters[k].right_protruding = p if trace_protrusion then - logs.report("opbd","rtbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) + report_protrusions("rtbd -> %s -> U+%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) end end end @@ -419,7 +378,9 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) end end end - tfmdata.auto_protrude = done + tfmdata.parameters.protrusion { + auto = true + } end -- The opbd test is just there because it was discussed on the @@ -427,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 @@ -441,11 +402,17 @@ function initializers.common.protrusion(tfmdata,value) local left = class.left or 1 local right = class.right or 1 if trace_protrusion then - logs.report("fonts","set protrusion class %s, vector: %s, factor: %s, left: %s, right: %s",value,class_vector,factor,left,right) + report_protrusions("setting class %s, vector: %s, factor: %s, left: %s, right: %s", + value,class.vector,factor,left,right) 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 @@ -476,70 +443,89 @@ function initializers.common.protrusion(tfmdata,value) end end elseif trace_protrusion then - logs.report("fonts","unknown protrusion vector '%s' in class '%s",class_vector,value) + report_protrusions("unknown vector '%s' in class '%s",class.vector,value) end elseif trace_protrusion then - logs.report("fonts","unknown protrusion class '%s'",value) + report_protrusions("unknown class '%s'",value) end end end end -table.insert(fonts.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(fonts.manipulators,"nostackmath") - -initializers.base.otf.nostackmath = initializers.common.nostackmath -initializers.node.otf.nostackmath = initializers.common.nostackmath - -table.insert(fonts.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(fonts.triggers,"slant") - -function initializers.common.slant(tfmdata,value) +local function initializeslant(tfmdata,value) value = tonumber(value) if not value then value = 0 @@ -548,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(fonts.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 @@ -568,56 +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 glyph = node.id("glyph") -local fontdata = fonts.ids - -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 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 - -fonts.otf.tables.features['formatters'] = 'Hide Formatting Characters' - -fonts.otf.features.register("formatters") +registerafmfeature { + name = "extend", + description = "scale glyphs horizontally", + initializers = { + base = initializeextend, + node = initializeextend, + } +} -table.insert(fonts.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, +-- } +-- } |