diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2010-05-24 14:05:02 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2010-05-24 14:05:02 +0000 |
commit | 57ea7dad48fbf2541c04e434c31bde655ada3ac4 (patch) | |
tree | 1f8b43bc7cb92939271e1f5bec610710be69097f /Master/texmf-dist/tex/context/base/font-ext.lua | |
parent | 6ee41e1f1822657f7f23231ec56c0272de3855e3 (diff) |
here is context 2010.05.24 13:05
git-svn-id: svn://tug.org/texlive/trunk@18445 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ext.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-ext.lua | 440 |
1 files changed, 292 insertions, 148 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ext.lua b/Master/texmf-dist/tex/context/base/font-ext.lua index 17c302c5325..05bdaf2fc3a 100644 --- a/Master/texmf-dist/tex/context/base/font-ext.lua +++ b/Master/texmf-dist/tex/context/base/font-ext.lua @@ -1,12 +1,20 @@ if not modules then modules = { } end modules ['font-ext'] = { version = 1.001, - comment = "companion to font-ini.tex and hand-ini.tex", + 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" } +local utf = unicode.utf8 local next, type, byte = next, type, string.byte +local gmatch, concat = string.gmatch, table.concat +local utfchar = utf.char + +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 { } --[[ldx-- <p>When we implement functions that deal with features, most of them @@ -16,9 +24,11 @@ of neutral.</p> 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> @@ -81,116 +91,22 @@ function initializers.common.lineheight(tfmdata,value) end end ---[[ldx-- -<p>It does not make sense any more to support messed up encoding vectors -so we stick to those that implement oldstyle and small caps. After all, -we move on. We can extend the next function on demand. This features is -only used with <l n='afm'/> files.</p> ---ldx]]-- +-- -- -- -- -- -- +-- shared +-- -- -- -- -- -- ---~ do ---~ ---~ local smallcaps = lpeg.P(".sc") + lpeg.P(".smallcaps") + lpeg.P(".caps") + lpeg.P("small") ---~ local oldstyle = lpeg.P(".os") + lpeg.P(".oldstyle") + lpeg.P(".onum") ---~ ---~ smallcaps = lpeg.Cs((1-smallcaps)^1) * smallcaps^1 ---~ oldstyle = lpeg.Cs((1-oldstyle )^1) * oldstyle ^1 ---~ ---~ function initializers.common.encoding(tfmdata,value) ---~ if value then ---~ local afmdata = tfmdata.shared.afmdata ---~ if afmdata then ---~ local encodingfile = value .. '.enc' ---~ local encoding = fonts.enc.load(encodingfile) ---~ if encoding then ---~ local vector = encoding.vector ---~ local characters = tfmdata.characters ---~ local unicodes = afmdata.luatex.unicodes ---~ local function remap(pattern,name) ---~ local p = pattern:match(name) ---~ if p then ---~ local oldchr, newchr = unicodes[p], unicodes[name] ---~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then ---~ -- logs.report("encoding","%s (%s) -> %s (%s)",p,oldchr or -1,name,newchr or -1) ---~ characters[oldchr] = characters[newchr] ---~ end ---~ end ---~ return p ---~ end ---~ for _, name in next, vector do ---~ local ok = remap(smallcaps,name) or remap(oldstyle,name) ---~ end ---~ if fonts.map.data[tfmdata.name] then ---~ fonts.map.data[tfmdata.name].encoding = encodingfile ---~ end ---~ end ---~ end ---~ end ---~ end ---~ ---~ -- when needed we can provide this as features in e.g. afm files ---~ ---~ function initializers.common.remap(tfmdata,value,pattern) -- will go away ---~ if value then ---~ local afmdata = tfmdata.shared.afmdata ---~ if afmdata then ---~ local characters = tfmdata.characters ---~ local descriptions = tfmdata.descriptions ---~ local unicodes = afmdata.luatex.unicodes ---~ local done = false ---~ for u, _ in next, characters do ---~ local name = descriptions[u].name ---~ if name then ---~ local p = pattern:match(name) ---~ if p then ---~ local oldchr, newchr = unicodes[p], unicodes[name] ---~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then ---~ characters[oldchr] = characters[newchr] ---~ end ---~ end ---~ end ---~ end ---~ end ---~ end ---~ end ---~ ---~ function initializers.common.oldstyle(tfmdata,value) ---~ initializers.common.remap(tfmdata,value,oldstyle) ---~ end ---~ function initializers.common.smallcaps(tfmdata,value) ---~ initializers.common.remap(tfmdata,value,smallcaps) ---~ end ---~ ---~ function initializers.common.fakecaps(tfmdata,value) ---~ if value then ---~ -- todo: scale down ---~ local afmdata = tfmdata.shared.afmdata ---~ if afmdata then ---~ local characters = tfmdata.characters ---~ local descriptions = tfmdata.descriptions ---~ local unicodes = afmdata.luatex.unicodes ---~ for u, _ in next, characters do ---~ local name = descriptions[u].name ---~ if name then ---~ local p = lower(name) ---~ if p then ---~ local oldchr, newchr = unicodes[p], unicodes[name] ---~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then ---~ characters[oldchr] = characters[newchr] ---~ end ---~ end ---~ end ---~ end ---~ end ---~ end ---~ end ---~ ---~ end ---~ ---~ function initializers.common.install(format,feature) -- 'afm','lineheight' ---~ initializers.base[format][feature] = initializers.common[feature] ---~ initializers.node[format][feature] = initializers.common[feature] ---~ end +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] + 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] + return class, vector + end +end -- -- -- -- -- -- -- expansion (hz) @@ -228,21 +144,37 @@ vectors['default'] = { [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7, } +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) if value then - local class = classes[value] + local class, vector = get_class_and_vector(tfmdata,value,"expansions") if class then - local vector = vectors[class.vector] if vector then - tfmdata.stretch = (class.stretch or 0) * 10 - tfmdata.shrink = (class.shrink or 0) * 10 - tfmdata.step = (class.step or 0) * 10 - tfmdata.auto_expand = true - local factor = class.factor or 1 - local data = characters.data + local stretch, shrink, step, factor = class.stretch or 0, class.shrink or 0, class.step or 0, 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) + end + tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true + local data = characters and characters.data for i, chr in next, tfmdata.characters do local v = vector[i] - if not v then + if data and not v then -- we could move the data test outside (needed for plain) local d = data[i] if d then local s = d.shcode @@ -261,7 +193,11 @@ function initializers.common.expansion(tfmdata,value) chr.expansion_factor = factor end end + elseif trace_expansion then + logs.report("fonts","unknown expansion vector '%s' in class '%s",class_vector,value) end + elseif trace_expansion then + logs.report("fonts","unknown expansion class '%s'",value) end end end @@ -274,6 +210,8 @@ initializers.node.otf.expansion = initializers.common.expansion initializers.base.afm.expansion = initializers.common.expansion initializers.node.afm.expansion = initializers.common.expansion +fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end) + -- -- -- -- -- -- -- protrusion -- -- -- -- -- -- @@ -288,7 +226,7 @@ local vectors = fonts.protrusions.vectors -- the values need to be revisioned -classes.preset = { factor = 1 } +classes.preset = { factor = 1, left = 1, right = 1 } function commands.setupfontprotrusion(class,settings) aux.getparameters(classes,class,'preset',settings) @@ -392,41 +330,156 @@ vectors['quality'] = table.merge( {}, vectors['alpha'] ) +-- As this is experimental code, users should not depend on it. The +-- implications are still discussed on the ConTeXt Dev List and we're +-- not sure yet what exactly the spec is (the next code is tested with +-- a gyre font patched by / fea file made by Khaled Hosny). The double +-- trick should not be needed it proper hanging punctuation is used in +-- which case values < 1 can be used. +-- +-- preferred (in context, usine vectors): +-- +-- \definefontfeature[whatever][default][mode=node,protrusion=quality] +-- +-- using lfbd and rtbd, with possibibility to enable only one side : +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn] +-- +-- idem, using multiplier +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn] +-- +-- idem, using named feature file (less frozen): +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea] + +classes['double'] = { -- for testing opbd + factor = 2, left = 1, right = 1, +} + +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 done, factor, left, right = false, 1, 1, 1 + local class = classes[value] + if class then + factor = class.factor or 1 + left = class.left or 1 + right = class.right or 1 + else + factor = tonumber(value) or 1 + end + if opbd ~= "right" then + local validlookups, lookuplist = fonts.otf.collect_lookups(otfdata,"lfbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local data = singles[lookup] + if data then + if trace_protrusion then + logs.report("fonts","set left protrusion 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," ")) + end + end + done = true + end + end + end + end + if opbd ~= "left" then + local validlookups, lookuplist = fonts.otf.collect_lookups(otfdata,"rtbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local data = singles[lookup] + if data then + if trace_protrusion then + logs.report("fonts","set right protrusion 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," ")) + end + end + end + done = true + end + end + end + tfmdata.auto_protrude = done +end + +-- The opbd test is just there because it was discussed on the +-- context development list. However, the mentioned fxlbi.otf font +-- 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) if value then - local class = classes[value] - if class then - local vector = vectors[class.vector] - if vector then - local factor = class.factor or 1 - local data = characters.data - local emwidth = tfmdata.parameters.quad - tfmdata.auto_protrude = true - for i, chr in next, tfmdata.characters do - local v, pl, pr = vector[i], nil, nil - if v then - pl, pr = v[1], v[2] - else - local d = data[i] - if d then - local s = d.shcode - if not s then - -- sorry - elseif type(s) == "table" then - local vl, vr = vector[s[1]], vector[s[#s]] - if vl then pl = vl[1] end - if vr then pr = vr[2] end - else - v = vector[s] - if v then - pl, pr = v[1], v[2] + local opbd = tfmdata.shared.features.opbd + if opbd then + -- possible values: left right both yes no (experimental) + map_opbd_onto_protrusion(tfmdata,value,opbd) + else + local class, vector = get_class_and_vector(tfmdata,value,"protrusions") + if class then + if vector then + local factor = class.factor or 1 + 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) + end + local data = characters.data + local emwidth = tfmdata.parameters.quad + tfmdata.auto_protrude = true + for i, chr in next, tfmdata.characters do + local v, pl, pr = vector[i], nil, nil + if v then + pl, pr = v[1], v[2] + else + local d = data[i] + if d then + local s = d.shcode + if not s then + -- sorry + elseif type(s) == "table" then + local vl, vr = vector[s[1]], vector[s[#s]] + if vl then pl = vl[1] end + if vr then pr = vr[2] end + else + v = vector[s] + if v then + pl, pr = v[1], v[2] + end end end end + if pl and pl ~= 0 then + chr.left_protruding = left *pl*factor + end + if pr and pr ~= 0 then + chr.right_protruding = right*pr*factor + end end - if pl and pl ~= 0 then chr.left_protruding = pl*factor end - if pr and pr ~= 0 then chr.right_protruding = pr*factor end + elseif trace_protrusion then + logs.report("fonts","unknown protrusion vector '%s' in class '%s",class_vector,value) end + elseif trace_protrusion then + logs.report("fonts","unknown protrusion class '%s'",value) end end end @@ -440,6 +493,10 @@ initializers.node.otf.protrusion = initializers.common.protrusion initializers.base.afm.protrusion = initializers.common.protrusion initializers.node.afm.protrusion = initializers.common.protrusion +fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end) + +-- -- -- + function initializers.common.nostackmath(tfmdata,value) tfmdata.ignore_stack_math = value end @@ -477,3 +534,90 @@ initializers.node.otf.itlc = initializers.common.itlc initializers.base.afm.itlc = initializers.common.itlc initializers.node.afm.itlc = initializers.common.itlc + +-- slanting + +table.insert(fonts.triggers,"slant") + +function initializers.common.slant(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + elseif value > 1 then + value = 1 + elseif value < -1 then + value = -1 + end + tfmdata.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 + +table.insert(fonts.triggers,"extend") + +function initializers.common.extend(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + elseif value > 10 then + value = 10 + elseif value < -10 then + value = -10 + end + tfmdata.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 +} + +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") + +table.insert(fonts.manipulators,"formatters") -- at end |