diff options
| author | Philipp Gesang <phg42.2a@gmail.com> | 2013-08-25 12:04:55 +0200 | 
|---|---|---|
| committer | Philipp Gesang <phg42.2a@gmail.com> | 2013-08-25 12:04:55 +0200 | 
| commit | cb9cb98643e1b3bcd846c11e7a7733f1d6ef20f3 (patch) | |
| tree | 09dee3558be686aff39da2d20157d56cbeb3e179 /luaotfload-merged.lua | |
| parent | a08ab16564f8c4e4f1b95363fb35332308ee7176 (diff) | |
| download | luaotfload-cb9cb98643e1b3bcd846c11e7a7733f1d6ef20f3.tar.gz | |
[fontloader] sync with Context as of 2013-08-25
Diffstat (limited to 'luaotfload-merged.lua')
| -rw-r--r-- | luaotfload-merged.lua | 929 | 
1 files changed, 928 insertions, 1 deletions
diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index 0a19be1..b39d4a8 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -1,6 +1,6 @@  -- merged file : luatex-fonts-merged.lua  -- parent file : luatex-fonts.lua --- merge date  : 08/24/13 12:19:21 +-- merge date  : 08/24/13 13:59:18  do -- begin closure to overcome local limits and interference @@ -3060,6 +3060,7 @@ local remapper={    fea="font feature files",    pfa="type1 fonts",    pfb="type1 fonts", +  afm="afm",  }  function resolvers.findfile(name,fileformat)    name=string.gsub(name,"\\","/") @@ -3078,6 +3079,10 @@ function resolvers.findfile(name,fileformat)    return found  end  resolvers.findbinfile=resolvers.findfile +function resolvers.loadbinfile(filename,filetype) +  local data=io.loaddata(filename) +  return true,data,#data +end  function resolvers.resolve(s)    return s  end @@ -5065,6 +5070,928 @@ end -- closure  do -- begin closure to overcome local limits and interference +if not modules then modules={} end modules ['font-tfm']={ +  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" +} +local next=next +local match=string.match +local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) +local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end) +local report_defining=logs.reporter("fonts","defining") +local report_tfm=logs.reporter("fonts","tfm loading") +local findbinfile=resolvers.findbinfile +local fonts=fonts +local handlers=fonts.handlers +local readers=fonts.readers +local constructors=fonts.constructors +local encodings=fonts.encodings +local tfm=constructors.newhandler("tfm") +local tfmfeatures=constructors.newfeatures("tfm") +local registertfmfeature=tfmfeatures.register +constructors.resolvevirtualtoo=false  +fonts.formats.tfm="type1" +function tfm.setfeatures(tfmdata,features) +  local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) +  if okay then +    return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm) +  else +    return {}  +  end +end +local function read_from_tfm(specification) +  local filename=specification.filename +  local size=specification.size +  if trace_defining then +    report_defining("loading tfm file %a at size %s",filename,size) +  end +  local tfmdata=font.read_tfm(filename,size)  +  if tfmdata then +    local features=specification.features and specification.features.normal or {} +    local resources=tfmdata.resources or {} +    local properties=tfmdata.properties or {} +    local parameters=tfmdata.parameters or {} +    local shared=tfmdata.shared   or {} +    properties.name=tfmdata.name +    properties.fontname=tfmdata.fontname +    properties.psname=tfmdata.psname +    properties.filename=specification.filename +    parameters.size=size +    shared.rawdata={} +    shared.features=features +    shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil +    tfmdata.properties=properties +    tfmdata.resources=resources +    tfmdata.parameters=parameters +    tfmdata.shared=shared +    parameters.slant=parameters.slant     or parameters[1] or 0 +    parameters.space=parameters.space     or parameters[2] or 0 +    parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 +    parameters.space_shrink=parameters.space_shrink  or parameters[4] or 0 +    parameters.x_height=parameters.x_height    or parameters[5] or 0 +    parameters.quad=parameters.quad      or parameters[6] or 0 +    parameters.extra_space=parameters.extra_space  or parameters[7] or 0 +    constructors.enhanceparameters(parameters) +    if constructors.resolvevirtualtoo then +      fonts.loggers.register(tfmdata,file.suffix(filename),specification)  +      local vfname=findbinfile(specification.name,'ovf') +      if vfname and vfname~="" then +        local vfdata=font.read_vf(vfname,size)  +        if vfdata then +          local chars=tfmdata.characters +          for k,v in next,vfdata.characters do +            chars[k].commands=v.commands +          end +          properties.virtualized=true +          tfmdata.fonts=vfdata.fonts +        end +      end +    end +    local allfeatures=tfmdata.shared.features or specification.features.normal +    constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm) +    if not features.encoding then +      local encoding,filename=match(properties.filename,"^(.-)%-(.*)$")  +      if filename and encoding and encodings.known and encodings.known[encoding] then +        features.encoding=encoding +      end +    end +    return tfmdata +  end +end +local function check_tfm(specification,fullname)  +  local foundname=findbinfile(fullname,'tfm') or "" +  if foundname=="" then +    foundname=findbinfile(fullname,'ofm') or ""  +  end +  if foundname=="" then +    foundname=fonts.names.getfilename(fullname,"tfm") or "" +  end +  if foundname~="" then +    specification.filename=foundname +    specification.format="ofm" +    return read_from_tfm(specification) +  elseif trace_defining then +    report_defining("loading tfm with name %a fails",specification.name) +  end +end +readers.check_tfm=check_tfm +function readers.tfm(specification) +  local fullname=specification.filename or "" +  if fullname=="" then +    local forced=specification.forced or "" +    if forced~="" then +      fullname=specification.name.."."..forced +    else +      fullname=specification.name +    end +  end +  return check_tfm(specification,fullname) +end + +end -- closure + +do -- begin closure to overcome local limits and interference + +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" +} +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  +afm.cache=containers.define("fonts","afm",afm.version,true) +afm.autoprefixed=true  +afm.helpdata={}  +afm.syncspace=true  +afm.addligatures=true  +afm.addtexligatures=true  +afm.addkerns=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, +  } +} +local comment=P("Comment") +local spacing=patterns.spacer  +local lineend=patterns.newline  +local words=C((1-lineend)^1) +local number=C((R("09")+S("."))^1)/tonumber*spacing^0 +local data=lpeg.Carg(1) +local pattern=( +  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 +local keys={} +function keys.FontName  (data,line) data.metadata.fontname=strip  (line)  +                   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) +  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)  +  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)  +  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={ +      }, +      descriptions={ +      }, +    } +    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)  +      return "" +    end) +    return data +  else +    if trace_loading then +      report_afm("no valid afm file %a",filename) +    end +    return nil +  end +end +local addkerns,addligatures,addtexligatures,unify,normalize  +function afm.load(filename) +  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  +  local unicodes,names={},{} +  local private=constructors.privateoffset +  local descriptions=data.descriptions +  for name,blob in next,data.characters do +    local code=unicodevector[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)  +  resources.unicodes=unicodes  +  resources.marks={}  +  resources.names=names  +  resources.private=private +end +normalize=function(data) +end +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 +addkerns=function(rawdata)  +  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  +            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 +  do_it_left(afm.helpdata.leftkerned) +  do_it_left(afm.helpdata.bothkerned) +  do_it_copy(afm.helpdata.bothkerned) +  do_it_copy(afm.helpdata.rightkerned) +end +local function adddimensions(data)  +  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 +        else +          description.height=ht +        end +        if dp==0 or dp<0 then +        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  +      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 +    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 +    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.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 +      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  +      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 +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 {}  +  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  +    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  +    end +  end +  if afmname~="" then +    local features=constructors.checkedfeatures("afm",specification.features.normal) +    specification.features.normal=features +    constructors.hashinstance(specification,true) +    specification=definers.resolve(specification)  +    local cache_id=specification.hash +    local tfmdata=containers.read(constructors.cache,cache_id)  +    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 +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 +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={ +  [0x0027]=0x2019, +} +local function texreplacements(tfmdata,value) +  local descriptions=tfmdata.descriptions +  local characters=tfmdata.characters +  for k,v in next,list do +    characters [k]=characters [v]  +    descriptions[k]=descriptions[v]  +  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, +  } +} +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 ""  +  if foundname=="" then +    foundname=fonts.names.getfilename(fullname,"afm") or "" +  end +  if foundname=="" and afm.autoprefixed then +    local encoding,shortname=match(fullname,"^(.-)%-(.*)$")  +    if encoding and shortname and fonts.encodings.known[encoding] then +      shortname=findbinfile(shortname,'afm') or ""  +      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  +        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)  +  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 + +end -- closure + +do -- begin closure to overcome local limits and interference +  if not modules then modules={} end modules ['luatex-fonts-tfm']={    version=1.001,    comment="companion to luatex-*.tex",  | 
