diff options
author | Philipp Gesang <phg42.2a@gmail.com> | 2013-08-25 12:06:38 +0200 |
---|---|---|
committer | Philipp Gesang <phg42.2a@gmail.com> | 2013-08-25 12:06:38 +0200 |
commit | b40962783c48f18452e3be2f7e84d2f1194005db (patch) | |
tree | 905123dcaf87779c68b989a4355ece824a96e55a | |
parent | cb9cb98643e1b3bcd846c11e7a7733f1d6ef20f3 (diff) | |
download | luaotfload-b40962783c48f18452e3be2f7e84d2f1194005db.tar.gz |
[type1] extinguish luaotfload-font-afm.lua
-rw-r--r-- | luaotfload-font-afm.lua | 971 |
1 files changed, 0 insertions, 971 deletions
diff --git a/luaotfload-font-afm.lua b/luaotfload-font-afm.lua deleted file mode 100644 index cb0c243..0000000 --- a/luaotfload-font-afm.lua +++ /dev/null @@ -1,971 +0,0 @@ -if not modules then modules = { } end modules ['font-afm'] = { - version = 1.001, - comment = "companion to font-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - ---[[ldx-- -<p>Some code may look a bit obscure but this has to do with the -fact that we also use this code for testing and much code evolved -in the transition from <l n='tfm'/> to <l n='afm'/> to <l -n='otf'/>.</p> - -<p>The following code still has traces of intermediate font support -where we handles font encodings. Eventually font encoding goes -away.</p> ---ldx]]-- - -local fonts, logs, trackers, containers, resolvers = fonts, logs, trackers, containers, resolvers - -local next, type, tonumber = next, type, tonumber -local format, match, gmatch, lower, gsub, strip = string.format, string.match, string.gmatch, string.lower, string.gsub, string.strip -local abs = math.abs -local P, S, C, R, lpegmatch, patterns = lpeg.P, lpeg.S, lpeg.C, lpeg.R, lpeg.match, lpeg.patterns -local derivetable = table.derive - -local trace_features = false trackers.register("afm.features", function(v) trace_features = v end) -local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end) -local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end) -local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) - -local report_afm = logs.reporter("fonts","afm loading") - -local findbinfile = resolvers.findbinfile - -local definers = fonts.definers -local readers = fonts.readers -local constructors = fonts.constructors - -local afm = constructors.newhandler("afm") -local pfb = constructors.newhandler("pfb") - -local afmfeatures = constructors.newfeatures("afm") -local registerafmfeature = afmfeatures.register - -afm.version = 1.410 -- incrementing this number one up will force a re-cache -afm.cache = containers.define("fonts", "afm", afm.version, true) -afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*) - -afm.helpdata = { } -- set later on so no local for this -afm.syncspace = true -- when true, nicer stretch values -afm.addligatures = true -- best leave this set to true -afm.addtexligatures = true -- best leave this set to true -afm.addkerns = true -- best leave this set to true - -local function setmode(tfmdata,value) - if value then - tfmdata.properties.mode = lower(value) - end -end - -registerafmfeature { - name = "mode", - description = "mode", - initializers = { - base = setmode, - node = setmode, - } -} - ---[[ldx-- -<p>We start with the basic reader which we give a name similar to the -built in <l n='tfm'/> and <l n='otf'/> reader.</p> ---ldx]]-- - ---~ Comment FONTIDENTIFIER LMMATHSYMBOLS10 ---~ Comment CODINGSCHEME TEX MATH SYMBOLS ---~ Comment DESIGNSIZE 10.0 pt ---~ Comment CHECKSUM O 4261307036 ---~ Comment SPACE 0 plus 0 minus 0 ---~ Comment QUAD 1000 ---~ Comment EXTRASPACE 0 ---~ Comment NUM 676.508 393.732 443.731 ---~ Comment DENOM 685.951 344.841 ---~ Comment SUP 412.892 362.892 288.889 ---~ Comment SUB 150 247.217 ---~ Comment SUPDROP 386.108 ---~ Comment SUBDROP 50 ---~ Comment DELIM 2390 1010 ---~ Comment AXISHEIGHT 250 - -local comment = P("Comment") -local spacing = patterns.spacer -- S(" \t")^1 -local lineend = patterns.newline -- S("\n\r") -local words = C((1 - lineend)^1) -local number = C((R("09") + S("."))^1) / tonumber * spacing^0 -local data = lpeg.Carg(1) - -local pattern = ( -- needs testing ... not used anyway as we no longer need math afm's - comment * spacing * - ( - data * ( - ("CODINGSCHEME" * spacing * words ) / function(fd,a) end + - ("DESIGNSIZE" * spacing * number * words ) / function(fd,a) fd[ 1] = a end + - ("CHECKSUM" * spacing * number * words ) / function(fd,a) fd[ 2] = a end + - ("SPACE" * spacing * number * "plus" * number * "minus" * number) / function(fd,a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end + - ("QUAD" * spacing * number ) / function(fd,a) fd[ 6] = a end + - ("EXTRASPACE" * spacing * number ) / function(fd,a) fd[ 7] = a end + - ("NUM" * spacing * number * number * number ) / function(fd,a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end + - ("DENOM" * spacing * number * number ) / function(fd,a,b ) fd[11], fd[12] = a, b end + - ("SUP" * spacing * number * number * number ) / function(fd,a,b,c) fd[13], fd[14], fd[15] = a, b, c end + - ("SUB" * spacing * number * number ) / function(fd,a,b) fd[16], fd[17] = a, b end + - ("SUPDROP" * spacing * number ) / function(fd,a) fd[18] = a end + - ("SUBDROP" * spacing * number ) / function(fd,a) fd[19] = a end + - ("DELIM" * spacing * number * number ) / function(fd,a,b) fd[20], fd[21] = a, b end + - ("AXISHEIGHT" * spacing * number ) / function(fd,a) fd[22] = a end - ) - + (1-lineend)^0 - ) - + (1-comment)^1 -)^0 - -local function scan_comment(str) - local fd = { } - lpegmatch(pattern,str,1,fd) - return fd -end - --- On a rainy day I will rewrite this in lpeg ... or we can use the (slower) fontloader --- as in now supports afm/pfb loading but it's not too bad to have different methods --- for testing approaches. - -local keys = { } - -function keys.FontName (data,line) data.metadata.fontname = strip (line) -- get rid of spaces - data.metadata.fullname = strip (line) end -function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end -function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end -function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end -function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end -function keys.Descender (data,line) data.metadata.descender = tonumber (line) end -function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end -function keys.Comment (data,line) - -- Comment DesignSize 12 (pts) - -- Comment TFM designsize: 12 (in points) - line = lower(line) - local designsize = match(line,"designsize[^%d]*(%d+)") - if designsize then data.metadata.designsize = tonumber(designsize) end -end - -local function get_charmetrics(data,charmetrics,vector) - local characters = data.characters - local chr, ind = { }, 0 - for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do - if k == 'C' then - v = tonumber(v) - if v < 0 then - ind = ind + 1 -- ? - else - ind = v - end - chr = { - index = ind - } - elseif k == 'WX' then - chr.width = tonumber(v) - elseif k == 'N' then - characters[v] = chr - elseif k == 'B' then - local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$") - chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) } - elseif k == 'L' then - local plus, becomes = match(v,"^(.-) +(.-)$") - local ligatures = chr.ligatures - if ligatures then - ligatures[plus] = becomes - else - chr.ligatures = { [plus] = becomes } - end - end - end -end - -local function get_kernpairs(data,kernpairs) - local characters = data.characters - for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do - local chr = characters[one] - if chr then - local kerns = chr.kerns - if kerns then - kerns[two] = tonumber(value) - else - chr.kerns = { [two] = tonumber(value) } - end - end - end -end - -local function get_variables(data,fontmetrics) - for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do - local keyhandler = keys[key] - if keyhandler then - keyhandler(data,rest) - end - end -end - -local function get_indexes(data,pfbname) - data.resources.filename = resolvers.unresolve(pfbname) -- no shortcut - local pfbblob = fontloader.open(pfbname) - if pfbblob then - local characters = data.characters - local pfbdata = fontloader.to_table(pfbblob) - if pfbdata then - local glyphs = pfbdata.glyphs - if glyphs then - if trace_loading then - report_afm("getting index data from %a",pfbname) - end - for index, glyph in next, glyphs do - local name = glyph.name - if name then - local char = characters[name] - if char then - if trace_indexing then - report_afm("glyph %a has index %a",name,index) - end - char.index = index - end - end - end - elseif trace_loading then - report_afm("no glyph data in pfb file %a",pfbname) - end - elseif trace_loading then - report_afm("no data in pfb file %a",pfbname) - end - fontloader.close(pfbblob) - elseif trace_loading then - report_afm("invalid pfb file %a",pfbname) - end -end - -local function readafm(filename) - local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging - if ok and afmblob then - local data = { - resources = { - filename = resolvers.unresolve(filename), - version = afm.version, - creator = "context mkiv", - }, - properties = { - hasitalics = false, - }, - goodies = { - }, - metadata = { - filename = file.removesuffix(file.basename(filename)) - }, - characters = { - -- a temporary store - }, - descriptions = { - -- the final store - }, - } - afmblob = gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics", function(charmetrics) - if trace_loading then - report_afm("loading char metrics") - end - get_charmetrics(data,charmetrics,vector) - return "" - end) - afmblob = gsub(afmblob,"StartKernPairs(.-)EndKernPairs", function(kernpairs) - if trace_loading then - report_afm("loading kern pairs") - end - get_kernpairs(data,kernpairs) - return "" - end) - afmblob = gsub(afmblob,"StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics) - if trace_loading then - report_afm("loading variables") - end - data.afmversion = version - get_variables(data,fontmetrics) - data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now - return "" - end) - return data - else - if trace_loading then - report_afm("no valid afm file %a",filename) - end - return nil - end -end - ---[[ldx-- -<p>We cache files. Caching is taken care of in the loader. We cheat a bit -by adding ligatures and kern information to the afm derived data. That -way we can set them faster when defining a font.</p> ---ldx]]-- - -local addkerns, addligatures, addtexligatures, unify, normalize -- we will implement these later - -function afm.load(filename) - -- hm, for some reasons not resolved yet - filename = resolvers.findfile(filename,'afm') or "" - if filename ~= "" then - local name = file.removesuffix(file.basename(filename)) - local data = containers.read(afm.cache,name) - local attr = lfs.attributes(filename) - local size, time = attr.size or 0, attr.modification or 0 - -- - local pfbfile = file.replacesuffix(name,"pfb") - local pfbname = resolvers.findfile(pfbfile,"pfb") or "" - if pfbname == "" then - pfbname = resolvers.findfile(file.basename(pfbfile),"pfb") or "" - end - local pfbsize, pfbtime = 0, 0 - if pfbname ~= "" then - local attr = lfs.attributes(pfbname) - pfbsize = attr.size or 0 - pfbtime = attr.modification or 0 - end - if not data or data.size ~= size or data.time ~= time or data.pfbsize ~= pfbsize or data.pfbtime ~= pfbtime then - report_afm("reading %a",filename) - data = readafm(filename) - if data then - if pfbname ~= "" then - get_indexes(data,pfbname) - elseif trace_loading then - report_afm("no pfb file for %a",filename) - end - report_afm("unifying %a",filename) - unify(data,filename) - if afm.addligatures then - report_afm("add ligatures") - addligatures(data) - end - if afm.addtexligatures then - report_afm("add tex ligatures") - addtexligatures(data) - end - if afm.addkerns then - report_afm("add extra kerns") - addkerns(data) - end - normalize(data) - report_afm("add tounicode data") - fonts.mappings.addtounicode(data,filename) - data.size = size - data.time = time - data.pfbsize = pfbsize - data.pfbtime = pfbtime - report_afm("saving %a in cache",name) - data = containers.write(afm.cache, name, data) - data = containers.read(afm.cache,name) - end - end - return data - else - return nil - end -end - -local uparser = fonts.mappings.makenameparser() - -unify = function(data, filename) - local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context - local unicodes, names = { }, { } - local private = constructors.privateoffset - local descriptions = data.descriptions - for name, blob in next, data.characters do - local code = unicodevector[name] -- or characters.name_to_unicode[name] - if not code then - code = lpegmatch(uparser,name) - if not code then - code = private - private = private + 1 - report_afm("assigning private slot %U for unknown glyph name %a",code,name) - end - end - local index = blob.index - unicodes[name] = code - names[name] = index - blob.name = name - descriptions[code] = { - boundingbox = blob.boundingbox, - width = blob.width, - kerns = blob.kerns, - index = index, - name = name, - } - end - for unicode, description in next, descriptions do - local kerns = description.kerns - if kerns then - local krn = { } - for name, kern in next, kerns do - local unicode = unicodes[name] - if unicode then - krn[unicode] = kern - else - print(unicode,name) - end - end - description.kerns = krn - end - end - data.characters = nil - local resources = data.resources - local filename = resources.filename or file.removesuffix(file.basename(filename)) - resources.filename = resolvers.unresolve(filename) -- no shortcut - resources.unicodes = unicodes -- name to unicode - resources.marks = { } -- todo - resources.names = names -- name to index - resources.private = private -end - -normalize = function(data) -end - ---[[ldx-- -<p>These helpers extend the basic table with extra ligatures, texligatures -and extra kerns. This saves quite some lookups later.</p> ---ldx]]-- - -local addthem = function(rawdata,ligatures) - if ligatures then - local descriptions = rawdata.descriptions - local resources = rawdata.resources - local unicodes = resources.unicodes - local names = resources.names - for ligname, ligdata in next, ligatures do - local one = descriptions[unicodes[ligname]] - if one then - for _, pair in next, ligdata do - local two, three = unicodes[pair[1]], unicodes[pair[2]] - if two and three then - local ol = one.ligatures - if ol then - if not ol[two] then - ol[two] = three - end - else - one.ligatures = { [two] = three } - end - end - end - end - end - end -end - -addligatures = function(rawdata) addthem(rawdata,afm.helpdata.ligatures ) end -addtexligatures = function(rawdata) addthem(rawdata,afm.helpdata.texligatures) end - ---[[ldx-- -<p>We keep the extra kerns in separate kerning tables so that we can use -them selectively.</p> ---ldx]]-- - --- This is rather old code (from the beginning when we had only tfm). If --- we unify the afm data (now we have names all over the place) then --- we can use shcodes but there will be many more looping then. But we --- could get rid of the tables in char-cmp then. Als, in the generic version --- we don't use the character database. (Ok, we can have a context specific --- variant). - -addkerns = function(rawdata) -- using shcodes is not robust here - local descriptions = rawdata.descriptions - local resources = rawdata.resources - local unicodes = resources.unicodes - local function do_it_left(what) - if what then - for unicode, description in next, descriptions do - local kerns = description.kerns - if kerns then - local extrakerns - for complex, simple in next, what do - complex = unicodes[complex] - simple = unicodes[simple] - if complex and simple then - local ks = kerns[simple] - if ks and not kerns[complex] then - if extrakerns then - extrakerns[complex] = ks - else - extrakerns = { [complex] = ks } - end - end - end - end - if extrakerns then - description.extrakerns = extrakerns - end - end - end - end - end - local function do_it_copy(what) - if what then - for complex, simple in next, what do - complex = unicodes[complex] - simple = unicodes[simple] - if complex and simple then - local complexdescription = descriptions[complex] - if complexdescription then -- optional - local simpledescription = descriptions[complex] - if simpledescription then - local extrakerns - local kerns = simpledescription.kerns - if kerns then - for unicode, kern in next, kerns do - if extrakerns then - extrakerns[unicode] = kern - else - extrakerns = { [unicode] = kern } - end - end - end - local extrakerns = simpledescription.extrakerns - if extrakerns then - for unicode, kern in next, extrakerns do - if extrakerns then - extrakerns[unicode] = kern - else - extrakerns = { [unicode] = kern } - end - end - end - if extrakerns then - complexdescription.extrakerns = extrakerns - end - end - end - end - end - end - end - -- add complex with values of simplified when present - do_it_left(afm.helpdata.leftkerned) - do_it_left(afm.helpdata.bothkerned) - -- copy kerns from simple char to complex char unless set - do_it_copy(afm.helpdata.bothkerned) - do_it_copy(afm.helpdata.rightkerned) -end - ---[[ldx-- -<p>The copying routine looks messy (and is indeed a bit messy).</p> ---ldx]]-- - -local function adddimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name - if data then - for unicode, description in next, data.descriptions do - local bb = description.boundingbox - if bb then - local ht, dp = bb[4], -bb[2] - if ht == 0 or ht < 0 then - -- no need to set it and no negative heights, nil == 0 - else - description.height = ht - end - if dp == 0 or dp < 0 then - -- no negative depths and no negative depths, nil == 0 - else - description.depth = dp - end - end - end - end -end - -local function copytotfm(data) - if data and data.descriptions then - local metadata = data.metadata - local resources = data.resources - local properties = derivetable(data.properties) - local descriptions = derivetable(data.descriptions) - local goodies = derivetable(data.goodies) - local characters = { } - local parameters = { } - local unicodes = resources.unicodes - -- - for unicode, description in next, data.descriptions do -- use parent table - characters[unicode] = { } - end - -- - local filename = constructors.checkedfilename(resources) - local fontname = metadata.fontname or metadata.fullname - local fullname = metadata.fullname or metadata.fontname - local endash = unicodes['space'] - local emdash = unicodes['emdash'] - local spacer = "space" - local spaceunits = 500 - -- - local monospaced = metadata.isfixedpitch - local charwidth = metadata.charwidth - local italicangle = metadata.italicangle - local charxheight = metadata.xheight and metadata.xheight > 0 and metadata.xheight - properties.monospaced = monospaced - parameters.italicangle = italicangle - parameters.charwidth = charwidth - parameters.charxheight = charxheight - -- same as otf - if properties.monospaced then - if descriptions[endash] then - spaceunits, spacer = descriptions[endash].width, "space" - end - if not spaceunits and descriptions[emdash] then - spaceunits, spacer = descriptions[emdash].width, "emdash" - end - if not spaceunits and charwidth then - spaceunits, spacer = charwidth, "charwidth" - end - else - if descriptions[endash] then - spaceunits, spacer = descriptions[endash].width, "space" - end - if not spaceunits and charwidth then - spaceunits, spacer = charwidth, "charwidth" - end - end - spaceunits = tonumber(spaceunits) - if spaceunits < 200 then - -- todo: warning - end - -- - parameters.slant = 0 - parameters.space = spaceunits - parameters.space_stretch = 500 - parameters.space_shrink = 333 - parameters.x_height = 400 - parameters.quad = 1000 - -- - if italicangle then - parameters.italicangle = italicangle - parameters.italicfactor = math.cos(math.rad(90+italicangle)) - parameters.slant = - math.round(math.tan(italicangle*math.pi/180)) - end - if monospaced then - parameters.space_stretch = 0 - parameters.space_shrink = 0 - elseif afm.syncspace then - parameters.space_stretch = spaceunits/2 - parameters.space_shrink = spaceunits/3 - end - parameters.extra_space = parameters.space_shrink - if charxheight then - parameters.x_height = charxheight - else - -- same as otf - local x = unicodes['x'] - if x then - local x = descriptions[x] - if x then - parameters.x_height = x.height - end - end - -- - end - local fd = data.fontdimens - if fd and fd[8] and fd[9] and fd[10] then -- math - for k,v in next, fd do - parameters[k] = v - end - end - -- - parameters.designsize = (metadata.designsize or 10)*65536 - parameters.ascender = abs(metadata.ascender or 0) - parameters.descender = abs(metadata.descender or 0) - parameters.units = 1000 - -- - properties.spacer = spacer - properties.encodingbytes = 2 - properties.format = fonts.formats[filename] or "type1" - properties.filename = filename - properties.fontname = fontname - properties.fullname = fullname - properties.psname = fullname - properties.name = filename or fullname or fontname - -- - if next(characters) then - return { - characters = characters, - descriptions = descriptions, - parameters = parameters, - resources = resources, - properties = properties, - goodies = goodies, - } - end - end - return nil -end - ---[[ldx-- -<p>Originally we had features kind of hard coded for <l n='afm'/> -files but since I expect to support more font formats, I decided -to treat this fontformat like any other and handle features in a -more configurable way.</p> ---ldx]]-- - -function afm.setfeatures(tfmdata,features) - local okay = constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm) - if okay then - return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm) - else - return { } -- will become false - end -end - -local function checkfeatures(specification) -end - -local function afmtotfm(specification) - local afmname = specification.filename or specification.name - if specification.forced == "afm" or specification.format == "afm" then -- move this one up - if trace_loading then - report_afm("forcing afm format for %a",afmname) - end - else - local tfmname = findbinfile(afmname,"ofm") or "" - if tfmname ~= "" then - if trace_loading then - report_afm("fallback from afm to tfm for %a",afmname) - end - return -- just that - end - end - if afmname ~= "" then - -- weird, isn't this already done then? - local features = constructors.checkedfeatures("afm",specification.features.normal) - specification.features.normal = features - constructors.hashinstance(specification,true) -- also weird here - -- - specification = definers.resolve(specification) -- new, was forgotten - local cache_id = specification.hash - local tfmdata = containers.read(constructors.cache, cache_id) -- cache with features applied - if not tfmdata then - local rawdata = afm.load(afmname) - if rawdata and next(rawdata) then - adddimensions(rawdata) - tfmdata = copytotfm(rawdata) - if tfmdata and next(tfmdata) then - local shared = tfmdata.shared - if not shared then - shared = { } - tfmdata.shared = shared - end - shared.rawdata = rawdata - shared.features = features - shared.processes = afm.setfeatures(tfmdata,features) - end - elseif trace_loading then - report_afm("no (valid) afm file found with name %a",afmname) - end - tfmdata = containers.write(constructors.cache,cache_id,tfmdata) - end - return tfmdata - end -end - ---[[ldx-- -<p>As soon as we could intercept the <l n='tfm'/> reader, I implemented an -<l n='afm'/> reader. Since traditional <l n='pdftex'/> could use <l n='opentype'/> -fonts with <l n='afm'/> companions, the following method also could handle -those cases, but now that we can handle <l n='opentype'/> directly we no longer -need this features.</p> ---ldx]]-- - -local function read_from_afm(specification) - local tfmdata = afmtotfm(specification) - if tfmdata then - tfmdata.properties.name = specification.name - tfmdata = constructors.scale(tfmdata, specification) - local allfeatures = tfmdata.shared.features or specification.features.normal - constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm) - fonts.loggers.register(tfmdata,'afm',specification) - end - return tfmdata -end - ---[[ldx-- -<p>Here comes the implementation of a few features. We only implement -those that make sense for this format.</p> ---ldx]]-- - -local function prepareligatures(tfmdata,ligatures,value) - if value then - local descriptions = tfmdata.descriptions - for unicode, character in next, tfmdata.characters do - local description = descriptions[unicode] - local dligatures = description.ligatures - if dligatures then - local cligatures = character.ligatures - if not cligatures then - cligatures = { } - character.ligatures = cligatures - end - for unicode, ligature in next, dligatures do - cligatures[unicode] = { - char = ligature, - type = 0 - } - end - end - end - end -end - -local function preparekerns(tfmdata,kerns,value) - if value then - local rawdata = tfmdata.shared.rawdata - local resources = rawdata.resources - local unicodes = resources.unicodes - local descriptions = tfmdata.descriptions - for u, chr in next, tfmdata.characters do - local d = descriptions[u] - local newkerns = d[kerns] - if newkerns then - local kerns = chr.kerns - if not kerns then - kerns = { } - chr.kerns = kerns - end - for k,v in next, newkerns do - local uk = unicodes[k] - if uk then - kerns[uk] = v - end - end - end - end - end -end - -local list = { - -- [0x0022] = 0x201D, - [0x0027] = 0x2019, - -- [0x0060] = 0x2018, -} - -local function texreplacements(tfmdata,value) - local descriptions = tfmdata.descriptions - local characters = tfmdata.characters - for k, v in next, list do - characters [k] = characters [v] -- we forget about kerns - descriptions[k] = descriptions[v] -- we forget about kerns - end -end - -local function ligatures (tfmdata,value) prepareligatures(tfmdata,'ligatures', value) end -local function texligatures(tfmdata,value) prepareligatures(tfmdata,'texligatures',value) end -local function kerns (tfmdata,value) preparekerns (tfmdata,'kerns', value) end -local function extrakerns (tfmdata,value) preparekerns (tfmdata,'extrakerns', value) end - -registerafmfeature { - name = "liga", - description = "traditional ligatures", - initializers = { - base = ligatures, - node = ligatures, - } -} - -registerafmfeature { - name = "kern", - description = "intercharacter kerning", - initializers = { - base = kerns, - node = kerns, - } -} - -registerafmfeature { - name = "extrakerns", - description = "additional intercharacter kerning", - initializers = { - base = extrakerns, - node = extrakerns, - } -} - -registerafmfeature { - name = 'tlig', - description = 'tex ligatures', - initializers = { - base = texligatures, - node = texligatures, - } -} - -registerafmfeature { - name = 'trep', - description = 'tex replacements', - initializers = { - base = texreplacements, - node = texreplacements, - } -} - --- readers - -local check_tfm = readers.check_tfm - -fonts.formats.afm = "type1" -fonts.formats.pfb = "type1" - -local function check_afm(specification,fullname) - local foundname = findbinfile(fullname, 'afm') or "" -- just to be sure - if foundname == "" then - foundname = fonts.names.getfilename(fullname,"afm") or "" - end - if foundname == "" and afm.autoprefixed then - local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.* - if encoding and shortname and fonts.encodings.known[encoding] then - shortname = findbinfile(shortname,'afm') or "" -- just to be sure - if shortname ~= "" then - foundname = shortname - if trace_defining then - report_afm("stripping encoding prefix from filename %a",afmname) - end - end - end - end - if foundname ~= "" then - specification.filename = foundname - specification.format = "afm" - return read_from_afm(specification) - end -end - -function readers.afm(specification,method) - local fullname, tfmdata = specification.filename or "", nil - if fullname == "" then - local forced = specification.forced or "" - if forced ~= "" then - tfmdata = check_afm(specification,specification.name .. "." .. forced) - end - if not tfmdata then - method = method or definers.method or "afm or tfm" - if method == "tfm" then - tfmdata = check_tfm(specification,specification.name) - elseif method == "afm" then - tfmdata = check_afm(specification,specification.name) - elseif method == "tfm or afm" then - tfmdata = check_tfm(specification,specification.name) or check_afm(specification,specification.name) - else -- method == "afm or tfm" or method == "" then - tfmdata = check_afm(specification,specification.name) or check_tfm(specification,specification.name) - end - end - else - tfmdata = check_afm(specification,fullname) - end - return tfmdata -end - -function readers.pfb(specification,method) -- only called when forced - local original = specification.specification - if trace_defining then - report_afm("using afm reader for %a",original) - end - specification.specification = gsub(original,"%.pfb",".afm") - specification.forced = "afm" - return readers.afm(specification,method) -end |