diff options
Diffstat (limited to 'src/fontloader/runtime')
-rw-r--r-- | src/fontloader/runtime/fontloader-basics-gen.lua | 1 | ||||
-rw-r--r-- | src/fontloader/runtime/fontloader-reference.lua | 1228 |
2 files changed, 832 insertions, 397 deletions
diff --git a/src/fontloader/runtime/fontloader-basics-gen.lua b/src/fontloader/runtime/fontloader-basics-gen.lua index 2a68b1c..871e548 100644 --- a/src/fontloader/runtime/fontloader-basics-gen.lua +++ b/src/fontloader/runtime/fontloader-basics-gen.lua @@ -97,6 +97,7 @@ local remapper = { -- fea = "font feature files", -- no longer supported pfb = "type1 fonts", -- needed for vector loading afm = "afm", + enc = "enc files", } function resolvers.findfile(name,fileformat) diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua index 9785988..e6738ea 100644 --- a/src/fontloader/runtime/fontloader-reference.lua +++ b/src/fontloader/runtime/fontloader-reference.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 06/15/16 20:18:05 +-- merge date : 07/13/16 15:09:54 do -- begin closure to overcome local limits and interference @@ -1487,6 +1487,7 @@ local function do_serialize(root,name,depth,level,indexed) else handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) end + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then handle(format("%s %s=0x%X,",depth,k,v)) @@ -1509,6 +1510,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,v)) else @@ -1524,6 +1526,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={},",depth,k)) else @@ -1540,6 +1543,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={ %s },",depth,k,concat(st,", "))) else @@ -1560,6 +1564,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false")) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else @@ -1576,6 +1581,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=load(%q),",depth,k,f)) else @@ -1591,6 +1597,7 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk~="string" then elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,tostring(v))) else @@ -4161,7 +4168,7 @@ end function files.readinteger1(f) local n=byte(f:read(1)) if n>=0x80 then - return n-0xFF-1 + return n-0x100 else return n end @@ -4177,7 +4184,7 @@ function files.readinteger2(f) local a,b=byte(f:read(2),1,2) local n=0x100*a+b if n>=0x8000 then - return n-0xFFFF-1 + return n-0x10000 else return n end @@ -4186,6 +4193,15 @@ function files.readcardinal3(f) local a,b,c=byte(f:read(3),1,3) return 0x10000*a+0x100*b+c end +function files.readinteger3(f) + local a,b,c=byte(f:read(3),1,3) + local n=0x10000*a+0x100*b+c + if n>=0x80000 then + return n-0x1000000 + else + return n + end +end function files.readcardinal4(f) local a,b,c,d=byte(f:read(4),1,4) return 0x1000000*a+0x10000*b+0x100*c+d @@ -4194,7 +4210,7 @@ function files.readinteger4(f) local a,b,c,d=byte(f:read(4),1,4) local n=0x1000000*a+0x10000*b+0x100*c+d if n>=0x8000000 then - return n-0xFFFFFFFF-1 + return n-0x100000000 else return n end @@ -4203,7 +4219,7 @@ function files.readfixed4(f) local a,b,c,d=byte(f:read(4),1,4) local n=0x100*a+b if n>=0x8000 then - return n-0xFFFF-1+(0x100*c+d)/0xFFFF + return n-0x10000+(0x100*c+d)/0xFFFF else return n+(0x100*c+d)/0xFFFF end @@ -4311,6 +4327,7 @@ local remapper={ cidmap="cid maps", pfb="type1 fonts", afm="afm", + enc="enc files", } function resolvers.findfile(name,fileformat) name=string.gsub(name,"\\","/") @@ -5673,7 +5690,7 @@ if not modules then modules={} end modules ['font-con']={ license="see context related readme files" } local next,tostring,rawget=next,tostring,rawget -local format,match,lower,gsub=string.format,string.match,string.lower,string.gsub +local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy local derivetable=table.derive local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) @@ -5693,89 +5710,6 @@ constructors.version=1.01 constructors.cache=containers.define("fonts","constructors",constructors.version,false) constructors.privateoffset=0xF0000 constructors.cacheintex=true -constructors.keys={ - properties={ - encodingbytes="number", - embedding="number", - cidinfo={}, - format="string", - fontname="string", - fullname="string", - filename="filename", - psname="string", - name="string", - virtualized="boolean", - hasitalics="boolean", - autoitalicamount="basepoints", - nostackmath="boolean", - noglyphnames="boolean", - mode="string", - hasmath="boolean", - mathitalics="boolean", - textitalics="boolean", - finalized="boolean", - }, - parameters={ - mathsize="number", - scriptpercentage="float", - scriptscriptpercentage="float", - units="cardinal", - designsize="scaledpoints", - expansion={ - stretch="integerscale", - shrink="integerscale", - step="integerscale", - auto="boolean", - }, - protrusion={ - auto="boolean", - }, - slantfactor="float", - extendfactor="float", - factor="float", - hfactor="float", - vfactor="float", - size="scaledpoints", - units="scaledpoints", - scaledpoints="scaledpoints", - slantperpoint="scaledpoints", - spacing={ - width="scaledpoints", - stretch="scaledpoints", - shrink="scaledpoints", - extra="scaledpoints", - }, - xheight="scaledpoints", - quad="scaledpoints", - ascender="scaledpoints", - descender="scaledpoints", - synonyms={ - space="spacing.width", - spacestretch="spacing.stretch", - spaceshrink="spacing.shrink", - extraspace="spacing.extra", - x_height="xheight", - space_stretch="spacing.stretch", - space_shrink="spacing.shrink", - extra_space="spacing.extra", - em="quad", - ex="xheight", - slant="slantperpoint", - }, - }, - description={ - width="basepoints", - height="basepoints", - depth="basepoints", - boundingbox={}, - }, - character={ - width="scaledpoints", - height="scaledpoints", - depth="scaledpoints", - italic="scaledpoints", - }, -} local designsizes=allocate() constructors.designsizes=designsizes local loadedfonts=allocate() @@ -5913,6 +5847,23 @@ local function mathkerns(v,vdelta) end return k end +local psfake=0 +local function fixedpsname(psname,fallback) + local usedname=psname + if psname and psname~="" then + if find(psname," ") then + usedname=gsub(psname,"[%s]+","-") + else + end + elseif not fallback or fallback=="" then + psfake=psfake+1 + psname="fakename-"..psfake + else + psname=fallback + usedname=gsub(psname,"[^a-zA-Z0-9]+","-") + end + return usedname,psname~=usedname +end function constructors.scale(tfmdata,specification) local target={} if tonumber(specification) then @@ -5986,14 +5937,12 @@ function constructors.scale(tfmdata,specification) target.cidinfo=properties.cidinfo target.format=properties.format target.cache=constructors.cacheintex and "yes" or "renew" - local fontname=properties.fontname or tfmdata.fontname - local fullname=properties.fullname or tfmdata.fullname - local filename=properties.filename or tfmdata.filename - local psname=properties.psname or tfmdata.psname + local fontname=properties.fontname or tfmdata.fontname + local fullname=properties.fullname or tfmdata.fullname + local filename=properties.filename or tfmdata.filename + local psname=properties.psname or tfmdata.psname local name=properties.name or tfmdata.name - if not psname or psname=="" then - psname=fontname or (fullname and fonts.names.cleanname(fullname)) - end + local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename)) target.fontname=fontname target.fullname=fullname target.filename=filename @@ -6106,8 +6055,9 @@ function constructors.scale(tfmdata,specification) end end if trace_defining then - report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a", - name,fullname,filename,hdelta,vdelta,hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") + report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a", + name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta, + hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") end constructors.beforecopyingcharacters(target,tfmdata) local sharedkerns={} @@ -6849,19 +6799,61 @@ if context then os.exit() end local fonts=fonts -fonts.encodings={} -fonts.encodings.agl={} -fonts.encodings.known={} -setmetatable(fonts.encodings.agl,{ __index=function(t,k) +local encodings={} +fonts.encodings=encodings +encodings.agl={} +encodings.known={} +setmetatable(encodings.agl,{ __index=function(t,k) if k=="unicodes" then texio.write(" <loading (extended) adobe glyph list>") local unicodes=dofile(resolvers.findfile("font-age.lua")) - fonts.encodings.agl={ unicodes=unicodes } + encodings.agl={ unicodes=unicodes } return unicodes else return nil end end }) +encodings.cache=containers.define("fonts","enc",encodings.version,true) +function encodings.load(filename) + local name=file.removesuffix(filename) + local data=containers.read(encodings.cache,name) + if data then + return data + end + local vector,tag,hash,unicodes={},"",{},{} + local foundname=resolvers.findfile(filename,'enc') + if foundname and foundname~="" then + local ok,encoding,size=resolvers.loadbinfile(foundname) + if ok and encoding then + encoding=string.gsub(encoding,"%%(.-)\n","") + local unicoding=encodings.agl.unicodes + local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def") + local i=0 + for ch in string.gmatch(vec,"/([%a%d%.]+)") do + if ch~=".notdef" then + vector[i]=ch + if not hash[ch] then + hash[ch]=i + else + end + local u=unicoding[ch] + if u then + unicodes[u]=i + end + end + i=i+1 + end + end + end + local data={ + name=name, + tag=tag, + vector=vector, + hash=hash, + unicodes=unicodes + } + return containers.write(encodings.cache,name,data) +end end -- closure @@ -7033,7 +7025,7 @@ local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.m local floor=math.floor local formatters=string.formatters local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end) -local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_unimapping=v end) +local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_mapping=v end) local report_fonts=logs.reporter("fonts","loading") local force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end) local fonts=fonts or {} @@ -7149,6 +7141,9 @@ function mappings.addtounicode(data,filename,checklookups) local resources=data.resources local unicodes=resources.unicodes if not unicodes then + if trace_mapping then + report_fonts("no unicode list, quitting tounicode for %a",filename) + end return end local properties=data.properties @@ -7337,8 +7332,8 @@ function mappings.addtounicode(data,filename,checklookups) end if trace_mapping then for unic,glyph in table.sortedhash(descriptions) do - local name=glyph.name - local index=glyph.index + local name=glyph.name or "-" + local index=glyph.index or 0 local unicode=glyph.unicode if unicode then if type(unicode)=="table" then @@ -7441,164 +7436,6 @@ 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.handlers.tfm -tfm.version=1.000 -tfm.maxnestingdepth=5 -tfm.maxnestingsize=65536*1024 -local tfmfeatures=constructors.features.tfm -constructors.resolvevirtualtoo=false -fonts.formats.tfm="type1" -fonts.formats.ofm="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 depth={} -local function read_from_tfm(specification) - local filename=specification.filename - local size=specification.size - depth[filename]=(depth[filename] or 0)+1 - 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 - properties.format=fonts.formats.tfm - parameters.size=size - tfmdata.properties=properties - tfmdata.resources=resources - tfmdata.parameters=parameters - tfmdata.shared=shared - shared.rawdata={} - shared.features=features - shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil - 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 - tfmdata.type="virtual" - local fontlist=vfdata.fonts - local name=file.nameonly(filename) - for i=1,#fontlist do - local n=fontlist[i].name - local s=fontlist[i].size - local d=depth[filename] - s=constructors.scaled(s,vfdata.designsize) - if d>tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i]={ id=0 } - elseif (d>1) and (s>tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i]={ id=0 } - else - local t,id=fonts.constructors.readanddefine(n,s) - fontlist[i]={ id=id } - end - end - 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 - properties.haskerns=true - properties.hasligatures=true - resources.unicodes={} - resources.lookuptags={} - depth[filename]=depth[filename]-1 - return tfmdata - else - depth[filename]=depth[filename]-1 - 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 -readers.ofm=readers.tfm - -end -- closure - -do -- begin closure to overcome local limits and interference - if not modules then modules={} end modules ['font-oti']={ version=1.001, comment="companion to font-ini.mkiv", @@ -7625,6 +7462,7 @@ local function setmode(tfmdata,value) tfmdata.properties.mode=lower(value) end end +otf.modeinitializer=setmode local function setlanguage(tfmdata,value) if value then local cleanvalue=lower(value) @@ -11355,10 +11193,15 @@ local function readcoverage(f,offset,simple) end return coverage end -local function readclassdef(f,offset) +local function readclassdef(f,offset,preset) setposition(f,offset) local classdefformat=readushort(f) local classdef={} + if type(preset)=="number" then + for k=0,preset-1 do + classdef[k]=1 + end + end if classdefformat==1 then local index=readushort(f) local nofclassdef=readushort(f) @@ -11380,6 +11223,13 @@ local function readclassdef(f,offset) else report("unknown classdef format %a ",classdefformat) end + if type(preset)=="table" then + for k in next,preset do + if not classdef[k] then + classdef[k]=1 + end + end + end return classdef end local function classtocoverage(defs) @@ -11479,7 +11329,7 @@ local function covered(subset,all) end return used end -local function readlookuparray(f,noflookups) +local function readlookuparray(f,noflookups,nofcurrent) local lookups={} if noflookups>0 then local length=0 @@ -11522,7 +11372,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n for i=2,nofcurrent do current[i]={ readushort(f) } end - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,nofcurrent) rules[#rules+1]={ current=current, lookups=lookups @@ -11544,7 +11394,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n local rules={} if subclasssets then coverage=readcoverage(f,tableoffset+coverage) - currentclassdef=readclassdef(f,tableoffset+currentclassdef) + currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) for class=1,#subclasssets do local offset=subclasssets[class] @@ -11563,7 +11413,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n for i=2,nofcurrent do current[i]=currentclasses[readushort(f)+1] end - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,nofcurrent) rules[#rules+1]={ current=current, lookups=lookups @@ -11587,7 +11437,7 @@ local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,n elseif subtype==3 then local current=readarray(f) local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,#current) current=readcoveragearray(f,tableoffset,current,true) return { format="coverage", @@ -11642,7 +11492,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof end end local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,nofcurrent) rules[#rules+1]={ before=before, current=current, @@ -11668,9 +11518,9 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof local rules={} if subclasssets then local coverage=readcoverage(f,tableoffset+coverage) - local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef) - local currentclassdef=readclassdef(f,tableoffset+currentclassdef) - local afterclassdef=readclassdef(f,tableoffset+afterclassdef) + local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs) + local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) + local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs) local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs) local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs) @@ -11707,7 +11557,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof end end local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,nofcurrent) rules[#rules+1]={ before=before, current=current, @@ -11735,7 +11585,7 @@ local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof local current=readarray(f) local after=readarray(f) local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups) + local lookups=readlookuparray(f,noflookups,#current) before=readcoveragearray(f,tableoffset,before,true) current=readcoveragearray(f,tableoffset,current,true) after=readcoveragearray(f,tableoffset,after,true) @@ -12061,8 +11911,8 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local nofclasses2=readushort(f) local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2) coverage=readcoverage(f,tableoffset+coverage) - classdef1=readclassdef(f,tableoffset+classdef1) - classdef2=readclassdef(f,tableoffset+classdef2) + classdef1=readclassdef(f,tableoffset+classdef1,coverage) + classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs) local usedcoverage={} for g1,c1 in next,classdef1 do if coverage[g1] then @@ -14090,6 +13940,7 @@ function readers.getcomponents(fontdata) end end end +readers.unifymissing=unifymissing function readers.rehash(fontdata,hashmethod) if not (fontdata and fontdata.glyphs) then return @@ -15363,7 +15214,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.023 +otf.version=3.025 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pdfcache=containers.define("fonts","pdf",otf.version,true) @@ -15541,7 +15392,7 @@ function otf.load(filename,sub,featurefile) collectgarbage("collect") end stoptiming(otfreaders) - if elapsedtime then + if elapsedtime then report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders)) end if cleanup>3 then @@ -15703,13 +15554,13 @@ local function copytotfm(data,cache_id) spaceunits,spacer=charwidth,"charwidth" end end - spaceunits=tonumber(spaceunits) or 500 + spaceunits=tonumber(spaceunits) or units/2 parameters.slant=0 - parameters.space=spaceunits + parameters.space=spaceunits parameters.space_stretch=1*units/2 - parameters.space_shrink=1*units/3 - parameters.x_height=2*units/5 - parameters.quad=units + parameters.space_shrink=1*units/3 + parameters.x_height=2*units/5 + parameters.quad=units if spaceunits<2*units/5 then end if italicangle and italicangle~=0 then @@ -16119,7 +15970,7 @@ local function registerbasehash(tfmdata) basehash[hash]=base end properties.basehash=base - properties.fullname=properties.fullname.."-"..base + properties.fullname=(properties.fullname or properties.name).."-"..base applied={} end local function registerbasefeature(feature,value) @@ -16187,6 +16038,10 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local trace_singles=trace_baseinit and trace_singles local trace_alternatives=trace_baseinit and trace_alternatives local trace_ligatures=trace_baseinit and trace_ligatures + if not changed then + changed={} + tfmdata.changed=changed + end for i=1,#lookuplist do local sequence=lookuplist[i] local steps=sequence.steps @@ -16340,7 +16195,8 @@ local function featuresinitializer(tfmdata,value) local properties=tfmdata.properties local script=properties.script local language=properties.language - local rawfeatures=rawdata.resources.features + local rawresources=rawdata.resources + local rawfeatures=rawresources and rawresources.features local basesubstitutions=rawfeatures and rawfeatures.gsub local basepositionings=rawfeatures and rawfeatures.gpos if basesubstitutions or basepositionings then @@ -16411,7 +16267,7 @@ local registertracker=trackers.register local trace_injections=false registertracker("fonts.injections",function(v) trace_injections=v end) local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end) local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end) -local trace_spaces=false registertracker("otf.spaces",function(v) trace_spaces=v end) +local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end) local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end) local report_injections=logs.reporter("fonts","injections") local report_spaces=logs.reporter("fonts","spaces") @@ -17293,6 +17149,10 @@ local function inject_everything(head,where) nofmarks=nofmarks+1 marks[nofmarks]=current else +local yoffset=i.yoffset +if yoffset and yoffset~=0 then + setfield(current,"yoffset",yoffset) +end if hascursives then local cursivex=i.cursivex if cursivex then @@ -17344,10 +17204,6 @@ local function inject_everything(head,where) cursiveanchor=nil end end - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(current,"yoffset",yoffset) - end local leftkern=i.leftkern if leftkern and leftkern~=0 then insert_node_before(head,current,newkern(leftkern)) @@ -17594,6 +17450,37 @@ function nodes.injections.setspacekerns(font,sequence) triggers={ [font]=sequence } end end +local getthreshold +if context then + local threshold=1 + local parameters=fonts.hashes.parameters + directives.register("otf.threshold",function(v) threshold=tonumber(v) or 1 end) + getthreshold=function(font) + local p=parameters[font] + local f=p.factor + local s=p.spacing + local t=threshold*(s and s.width or p.space or 0)-2 + return t>0 and t or 0,f + end +else + injections.threshold=0 + getthreshold=function(font) + local p=fontdata[font].parameters + local f=p.factor + local s=p.spacing + local t=injections.threshold*(s and s.width or p.space or 0)-2 + return t>0 and t or 0,f + end +end +injections.getthreshold=getthreshold +function injections.isspace(n,threshold) + if getid(n)==glue_code then + local w=getfield(n,"width") + if threshold and w>threshold then + return 32 + end + end +end local function injectspaces(head) if not triggers then return head,false @@ -17609,10 +17496,9 @@ local function injectspaces(head) local function updatefont(font,trig) leftkerns=trig.left rightkerns=trig.right - local par=fontdata[font].parameters - factor=par.factor - threshold=par.spacing.width-1 lastfont=font + threshold, + factor=getthreshold(font) end for n in traverse_id(glue_code,tonut(head)) do local prev,next=getboth(n) @@ -17631,7 +17517,7 @@ local function injectspaces(head) end end if prevchar then - local font=getfont(next) + local font=getfont(prev) local trig=triggers[font] if trig then if lastfont~=font then @@ -17644,7 +17530,7 @@ local function injectspaces(head) end if leftkern then local old=getfield(n,"width") - if old>=threshold then + if old>threshold then if rightkern then local new=old+(leftkern+rightkern)*factor if trace_spaces then @@ -17663,7 +17549,7 @@ local function injectspaces(head) leftkern=false elseif rightkern then local old=getfield(n,"width") - if old>=threshold then + if old>threshold then local new=old+rightkern*factor if trace_spaces then report_spaces("[%p -> %p] %C",nextchar,old,new) @@ -18114,11 +18000,7 @@ local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kern local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end) local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end) local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end) -local quit_on_no_replacement=true -local zwnjruns=true local optimizekerns=true -registerdirective("otf.zwnjruns",function(v) zwnjruns=v end) -registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement=value end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -18195,6 +18077,7 @@ local getligaindex=injections.getligaindex local cursonce=true local fonthashes=fonts.hashes local fontdata=fonthashes.identifiers +local fontfeatures=fonthashes.features local otffeatures=fonts.constructors.features.otf local registerotffeature=otffeatures.register local onetimemessage=fonts.loggers.onetimemessage or function() end @@ -18214,14 +18097,8 @@ local notmatchpre={} local notmatchpost={} local notmatchreplace={} local handlers={} -local function isspace(n) - if getid(n)==glue_code then - local w=getfield(n,"width") - if w>=threshold then - return 32 - end - end -end +local isspace=injections.isspace +local getthreshold=injections.getthreshold local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end @@ -18499,7 +18376,7 @@ end end return head,base end -local function multiple_glyphs(head,start,multiple,ignoremarks) +local function multiple_glyphs(head,start,multiple,ignoremarks,what) local nofmultiples=#multiple if nofmultiples>0 then resetinjection(start) @@ -18513,6 +18390,17 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) insert_node_after(head,start,n) start=n end + if what==true then + elseif what>1 then + local m=multiple[nofmultiples] + for i=2,what do + local n=copy_node(start) + resetinjection(n) + setchar(n,m) + insert_node_after(head,start,n) + start=n + end + end end return head,start,true else @@ -18583,7 +18471,7 @@ function handlers.gsub_multiple(head,start,dataset,sequence,multiple) if trace_multiples then logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple)) end - return multiple_glyphs(head,start,multiple,sequence.flags[1]) + return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1]) end function handlers.gsub_ligature(head,start,dataset,sequence,ligature) local current=getnext(start) @@ -19038,7 +18926,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup if trace_multiples then logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) end - return multiple_glyphs(head,start,replacement,sequence.flags[1]) + return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end return head,start,false end @@ -19050,7 +18938,7 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku end local kind=dataset[4] local what=dataset[1] - local value=what==true and tfmdata.shared.features[kind] or what + local value=what==true and tfmdata.shared.features[kind] or what local current=start while current do local currentchar=ischar(current) @@ -19991,16 +19879,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end prev=getprev(prev) - elseif seq[n][32] then + elseif seq[n][32] and isspace(prev,threshold) then n=n-1 prev=getprev(prev) else match=false break end - elseif seq[n][32] then - n=n-1 - prev=getprev(prev) else match=false break @@ -20114,15 +19999,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else end current=getnext(current) - elseif seq[n][32] then + elseif seq[n][32] and isspace(current,threshold) then n=n+1 + current=getnext(current) else match=false break end - elseif seq[n][32] then - n=n+1 - current=getnext(current) else match=false break @@ -20217,7 +20100,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if replacements then head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode) else - done=quit_on_no_replacement + done=true if trace_contexts then logprocess("%s: skipping match",cref(dataset,sequence)) end @@ -20366,10 +20249,10 @@ local function kernrun(disc,k_run,font,attr,...) break end end - if prev and (pre or replace) and not ischar(prev,font) then + if prev and not ischar(prev,font) then prev=false end - if next and (post or replace) and not ischar(next,font) then + if next and not ischar(next,font) then next=false end if pre then @@ -20795,8 +20678,8 @@ local function featuresprocessor(head,font,attr) descriptions=tfmdata.descriptions characters=tfmdata.characters marks=tfmdata.resources.marks - factor=tfmdata.parameters.factor - threshold=tfmdata.parameters.spacing.width or 65536*10 + threshold, + factor=getthreshold(font) elseif currentfont~=font then report_warning("nested call with a different font, level %s, quitting",nesting) nesting=nesting-1 @@ -20824,15 +20707,12 @@ local function featuresprocessor(head,font,attr) local steps=sequence.steps local nofsteps=sequence.nofsteps if not steps then - local h,d,ok=handler(head,start,dataset,sequence,nil,nil,nil,0,font,attr) + local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr) if ok then success=true if h then head=h end - if d then - start=d - end end elseif typ=="gsub_reversecontextchain" then local start=find_node_tail(head) @@ -21017,9 +20897,25 @@ otf.nodemodeinitializer=featuresinitializer otf.featuresprocessor=featuresprocessor otf.handlers=handlers local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end -function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) - setspacekerns(font,sequence) - return head,start,true +if fontfeatures then + function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) + local features=fontfeatures[font] + local enabled=features.spacekern==true and features.kern==true + if enabled then + setspacekerns(font,sequence) + end + return head,start,enabled + end +else + function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) + local shared=fontdata[font].shared + local features=shared and shared.features + local enabled=features and features.spacekern==true and features.kern==true + if enabled then + setspacekerns(font,sequence) + end + return head,start,enabled + end end local function hasspacekerns(data) local sequences=data.resources.sequences @@ -21053,8 +20949,8 @@ otf.readers.registerextender { local function spaceinitializer(tfmdata,value) local resources=tfmdata.resources local spacekerns=resources and resources.spacekerns - if spacekerns==nil then - local properties=tfmdata.properties + local properties=tfmdata.properties + if value and spacekerns==nil then if properties and properties.hasspacekerns then local sequences=resources.sequences local left={} @@ -21067,7 +20963,20 @@ local function spaceinitializer(tfmdata,value) if steps then local kern=sequence.features.kern if kern then - feat=feat or kern + if feat then + for script,languages in next,kern do + local f=feat[k] + if f then + for l in next,languages do + f[l]=true + end + else + feat[script]=languages + end + end + else + feat=kern + end for i=1,#steps do local step=steps[i] local coverage=step.coverage @@ -23117,7 +23026,7 @@ if not modules then modules={} end modules ['font-ocl']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local tostring,next=tostring,next +local tostring,next,format=tostring,next,string.format local formatters=string.formatters local otf=fonts.handlers.otf local f_color_start=formatters["pdf:direct: %f %f %f rg"] @@ -23234,70 +23143,62 @@ do end end end -if context and xml.convert then +do local report_svg=logs.reporter("fonts","svg conversion") - local xmlconvert=xml.convert - local xmlfirst=xml.first local loaddata=io.loaddata local savedata=io.savedata local remove=os.remove + if context and xml.convert then + local xmlconvert=xml.convert + local xmlfirst=xml.first + function otfsvg.filterglyph(entry,index) + local svg=xmlconvert(entry.data) + local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']") + local data=root and tostring(root) + return data + end + else + function otfsvg.filterglyph(entry,index) + return entry.data + end + end function otfsvg.topdf(svgshapes) - local inkscape=io.popen("inkscape --shell 2>&1","w") + local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w") local pdfshapes={} local nofshapes=#svgshapes local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"] local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"] local f_convert=formatters["%s --export-pdf=%s\n"] + local filterglyph=otfsvg.filterglyph report_svg("processing %i svg containers",nofshapes) statistics.starttiming() for i=1,nofshapes do local entry=svgshapes[i] - for j=entry.first,entry.last do - local svg=xmlconvert(entry.data) - local root=svg and xmlfirst(svg,"/svg[@id='glyph"..j.."']") - local data=root and tostring(root) + for index=entry.first,entry.last do + local data=filterglyph(entry,index) if data and data~="" then - local svgfile=f_svgfile(j) - local pdffile=f_pdffile(j) + local svgfile=f_svgfile(index) + local pdffile=f_pdffile(index) savedata(svgfile,data) inkscape:write(f_convert(svgfile,pdffile)) - pdfshapes[j]=true + pdfshapes[index]=true end end end inkscape:write("quit\n") inkscape:close() report_svg("processing %i pdf results",nofshapes) - for i in next,pdfshapes do - local svgfile=f_svgfile(i) - local pdffile=f_pdffile(i) - pdfshapes[i]=loaddata(pdffile) + for index in next,pdfshapes do + local svgfile=f_svgfile(index) + local pdffile=f_pdffile(index) + pdfshapes[index]=loaddata(pdffile) remove(svgfile) remove(pdffile) end statistics.stoptiming() - report_svg("conversion time: %0.3f",statistics.elapsedtime()) - return pdfshapes - end -else - function otfsvg.topdf(svgshapes) - local svgfile="temp-otf-svg-shape.svg" - local pdffile="temp-otf-svg-shape.pdf" - local command="inkscape "..svgfile.." --export-pdf="..pdffile - local pdfshapes={} - local nofshapes=#svgshapes - texio.write(formatters["[converting %i svg glyphs to pdf using command %q : "](nofshapes,command)) - for i=1,nofshapes do - local entry=svgshapes[i] - for j=entry.first,entry.last do - texio.write(formatters["%i "](j)) - io.savedata(svgfile,tostring(entry.data)) - os.execute(command) - pdfshapes[j]=io.loaddata(pdffile) - end + if statistics.elapsedseconds then + report_svg("svg conversion time %s",statistics.elapsedseconds()) end - os.remove(svgfile) - texio.write("done]") return pdfshapes end end @@ -23380,20 +23281,18 @@ if not modules then modules={} end modules ['font-onr']={ license="see context related readme files" } local fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers -local next,type,tonumber,rawget=next,type,tonumber,rawget +local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find local char,byte,sub=string.char,string.byte,string.sub local abs=math.abs local bxor,rshift=bit32.bxor,bit32.rshift -local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg +local P,S,R,Cmt,C,Ct,Cs,Carg,Cf,Cg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg local lpegmatch,patterns=lpeg.match,lpeg.patterns 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 report_afm=logs.reporter("fonts","afm loading") -local report_afm=logs.reporter("fonts","pfb loading") -fonts=fonts or {} -local handlers=fonts.handlers or {} -fonts.handlers=handlers +local report_pfb=logs.reporter("fonts","pfb loading") +local handlers=fonts.handlers local afm=handlers.afm or {} handlers.afm=afm local readers=afm.readers or {} @@ -23415,16 +23314,25 @@ do end local initialize=function(str,position,size) n=0 - m=tonumber(size) + m=size return position+1 end local charstrings=P("/CharStrings") + local encoding=P("/Encoding") + local dup=P("dup") + local put=P("put") + local array=P("array") local name=P("/")*C((R("az")+R("AZ")+R("09")+S("-_."))^1) - local size=C(R("09")^1) + local digits=R("09")^1 + local cardinal=digits/tonumber local spaces=P(" ")^1 + local spacing=patterns.whitespace^0 local p_filternames=Ct ( - (1-charstrings)^0*charstrings*spaces*Cmt(size,initialize)*(Cmt(name*P(" ")^1*C(R("09")^1),progress)+P(1))^1 + (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,progress)+P(1))^1 ) + local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf( + Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1 +,rawset) local decrypt do local r,c1,c2,n=0,0,0,0 @@ -23457,15 +23365,20 @@ do end binary=decrypt(binary,4) local vector=lpegmatch(p_filternames,binary) - if vector[1]==".notdef" then - vector[0]=table.remove(vector,1) + for i=1,#vector do + vector[i-1]=vector[i] end + vector[#vector]=nil if not vector then report_pfb("no vector in %a",filename) return end - return vector + local encoding=lpegmatch(p_filterencoding,ascii) + return vector,encoding end + local pfb=handlers.pfb or {} + handlers.pfb=pfb + pfb.loadvector=loadpfbvector get_indexes=function(data,pfbname) local vector=loadpfbvector(pfbname) if vector then @@ -23691,6 +23604,7 @@ local steps={ "add ligatures", "add extra kerns", "normalize features", + "check extra features", "fix names", } local function applyenhancers(data,filename) @@ -23904,6 +23818,7 @@ enhancers["normalize features"]=function(data) data.resources.features=features data.resources.sequences=sequences end +enhancers["check extra features"]=otf.enhancers.enhance enhancers["fix names"]=function(data) for k,v in next,data.descriptions do local n=v.name @@ -24265,17 +24180,12 @@ local function read_from_afm(specification) end return tfmdata end -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, + base=otf.modeinitializer, + node=otf.modeinitializer, } } registerafmfeature { @@ -24290,7 +24200,6 @@ registerafmfeature { node=otf.featuresprocessor, } } -local check_tfm=readers.check_tfm fonts.formats.afm="type1" fonts.formats.pfb="type1" local function check_afm(specification,fullname) @@ -24325,7 +24234,8 @@ function readers.afm(specification,method) tfmdata=check_afm(specification,specification.name.."."..forced) end if not tfmdata then - method=method or definers.method or "afm or tfm" + local check_tfm=readers.check_tfm + method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm" if method=="tfm" then tfmdata=check_tfm(specification,specification.name) elseif method=="afm" then @@ -24533,6 +24443,529 @@ 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,type=next,type +local match,format=string.match,string.format +local concat,sortedhash=table.concat,table.sortedhash +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 setmetatableindex=table.setmetatableindex +local fonts=fonts +local handlers=fonts.handlers +local readers=fonts.readers +local constructors=fonts.constructors +local encodings=fonts.encodings +local tfm=constructors.handlers.tfm +tfm.version=1.000 +tfm.maxnestingdepth=5 +tfm.maxnestingsize=65536*1024 +local otf=fonts.handlers.otf +local tfmfeatures=constructors.features.tfm +local registertfmfeature=tfmfeatures.register +constructors.resolvevirtualtoo=false +fonts.formats.tfm="type1" +fonts.formats.ofm="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 depth={} +local enhancers={} +local steps={ + "normalize features", + "check extra features" +} +enhancers["check extra features"]=otf.enhancers.enhance +local function applyenhancers(data,filename) + for i=1,#steps do + local step=steps[i] + local enhancer=enhancers[step] + if enhancer then + if trace_loading then + report_tfm("applying enhancer %a",step) + end + enhancer(data,filename) + else + report_tfm("invalid enhancer %a",step) + end + end +end +local function read_from_tfm(specification) + local filename=specification.filename + local size=specification.size + depth[filename]=(depth[filename] or 0)+1 + 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 features=constructors.checkedfeatures("tfm",features) + specification.features.normal=features + local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata=newtfmdata + end + local resources=tfmdata.resources or {} + local properties=tfmdata.properties or {} + local parameters=tfmdata.parameters or {} + local shared=tfmdata.shared or {} + shared.features=features + shared.resources=resources + properties.name=tfmdata.name + properties.fontname=tfmdata.fontname + properties.psname=tfmdata.psname + properties.fullname=tfmdata.fullname + properties.filename=specification.filename + properties.format=fonts.formats.tfm + tfmdata.properties=properties + tfmdata.resources=resources + tfmdata.parameters=parameters + tfmdata.shared=shared + shared.rawdata={ resources=resources } + shared.features=features + if newtfmdata then + if not resources.marks then + resources.marks={} + end + if not resources.sequences then + resources.sequences={} + end + if not resources.features then + resources.features={ + gsub={}, + gpos={}, + } + end + if not tfmdata.changed then + tfmdata.changed={} + end + if not tfmdata.descriptions then + tfmdata.descriptions=tfmdata.characters + end + otf.readers.addunicodetable(tfmdata) + applyenhancers(tfmdata,filename) + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + otf.readers.unifymissing(tfmdata) + fonts.mappings.addtounicode(tfmdata,filename) + tfmdata.tounicode=1 + local tounicode=fonts.mappings.tounicode + for unicode,v in next,tfmdata.characters do + local u=v.unicode + if u then + v.tounicode=tounicode(u) + end + end + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil + parameters.factor=1 + parameters.size=size + 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 newtfmdata then + elseif 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 + tfmdata.type="virtual" + local fontlist=vfdata.fonts + local name=file.nameonly(filename) + for i=1,#fontlist do + local n=fontlist[i].name + local s=fontlist[i].size + local d=depth[filename] + s=constructors.scaled(s,vfdata.designsize) + if d>tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i]={ id=0 } + elseif (d>1) and (s>tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i]={ id=0 } + else + local t,id=fonts.constructors.readanddefine(n,s) + fontlist[i]={ id=id } + end + end + end + end + end + properties.haskerns=true + properties.hasligatures=true + resources.unicodes={} + resources.lookuptags={} + depth[filename]=depth[filename]-1 + return tfmdata + else + depth[filename]=depth[filename]-1 + 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 +readers.ofm=readers.tfm +do + local outfiles={} + local tfmcache=table.setmetatableindex(function(t,tfmdata) + local id=font.define(tfmdata) + t[tfmdata]=id + return id + end) + local encdone=table.setmetatableindex("table") + function tfm.reencode(tfmdata,specification) + local features=specification.features + if not features then + return + end + local features=features.normal + if not features then + return + end + local tfmfile=file.basename(tfmdata.name) + local encfile=features.reencode + local pfbfile=features.pfbfile + local bitmap=features.bitmap + if not encfile then + return + end + local pfbfile=outfiles[tfmfile] + if pfbfile==nil then + if bitmap then + pfbfile=false + elseif type(pfbfile)~="string" then + pfbfile=tfmfile + end + if type(pfbfile)=="string" then + pfbfile=file.addsuffix(pfbfile,"pfb") + report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile) + else + report_tfm("using bitmap shapes for %a",tfmfile) + pfbfile=false + end + outfiles[tfmfile]=pfbfile + end + local encoding=false + local vector=false + if type(pfbfile)=="string" then + local pfb=fonts.constructors.handlers.pfb + if pfb and pfb.loadvector then + local v,e=pfb.loadvector(pfbfile) + if v then + vector=v + end + if e then + encoding=e + end + end + end + if type(encfile)=="string" and encfile~="auto" then + encoding=fonts.encodings.load(file.addsuffix(encfile,"enc")) + if encoding then + encoding=encoding.vector + end + end + if not encoding then + report_tfm("bad encoding for %a, quitting",tfmfile) + return + end + local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes + local virtualid=tfmcache[tfmdata] + local tfmdata=table.copy(tfmdata) + local characters={} + local originals=tfmdata.characters + local indices={} + local parentfont={ "font",1 } + local private=fonts.constructors.privateoffset + local reported=encdone[tfmfile][encfile] + local backmap=vector and table.swapped(vector) + local done={} + for index,name in sortedhash(encoding) do + local unicode=unicoding[name] + local original=originals[index] + if original then + if unicode then + original.unicode=unicode + else + unicode=private + private=private+1 + if not reported then + report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode) + end + end + characters[unicode]=original + indices[index]=unicode + original.name=name + if backmap then + original.index=backmap[name] + else + original.commands={ parentfont,{ "char",index } } + original.oindex=index + end + done[name]=true + elseif not done[name] then + report_tfm("bad index %a in font %a with name %a",index,tfmfile,name) + end + end + encdone[tfmfile][encfile]=true + for k,v in next,characters do + local kerns=v.kerns + if kerns then + local t={} + for k,v in next,kerns do + local i=indices[k] + if i then + t[i]=v + end + end + v.kerns=next(t) and t or nil + end + local ligatures=v.ligatures + if ligatures then + local t={} + for k,v in next,ligatures do + local i=indices[k] + if i then + t[i]=v + v.char=indices[v.char] + end + end + v.ligatures=next(t) and t or nil + end + end + tfmdata.fonts={ { id=virtualid } } + tfmdata.characters=characters + tfmdata.fullname=tfmdata.fullname or tfmdata.name + tfmdata.psname=file.nameonly(pfbfile or tfmdata.name) + tfmdata.filename=pfbfile + tfmdata.encodingbytes=2 + tfmdata.format="type1" + tfmdata.tounicode=1 + tfmdata.embedding="subset" + tfmdata.usedbitmap=bitmap and virtualid + return tfmdata + end +end +do + local template=[[ +/CIDInit /ProcSet findresource begin + 12 dict begin + begincmap + /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def + /CMapName /TeX-bitmap-%s def + /CMapType 2 def + 1 begincodespacerange + <00> <FF> + endcodespacerange + %s beginbfchar +%s + endbfchar + endcmap +CMapName currentdict /CMap defineresource pop end +end +end +]] + local flushstreamobject=lpdf and lpdf.flushstreamobject + local setfontattributes=pdf.setfontattributes + if not flushstreamobject then + flushstreamobject=function(data) + return pdf.obj { + immediate=true, + type="stream", + string=data, + } + end + end + if not setfontattributes then + setfontattributes=function(id,data) + print(format("your luatex is too old so no tounicode bitmap font%i",id)) + end + end + function tfm.addtounicode(tfmdata) + local id=tfmdata.usedbitmap + local map={} + local char={} + for k,v in next,tfmdata.characters do + local index=v.oindex + local tounicode=v.tounicode + if index and tounicode then + map[index]=tounicode + end + end + for k,v in sortedhash(map) do + char[#char+1]=format("<%02X> <%s>",k,v) + end + char=concat(char,"\n") + local stream=format(template,id,id,#char,char) + local reference=flushstreamobject(stream,nil,true) + setfontattributes(id,format("/ToUnicode %i 0 R",reference)) + end +end +do + local everywhere={ ["*"]={ ["*"]=true } } + local noflags={ false,false,false,false } + enhancers["normalize features"]=function(data) + local ligatures=setmetatableindex("table") + local kerns=setmetatableindex("table") + local characters=data.characters + for u,c in next,characters do + local l=c.ligatures + local k=c.kerns + if l then + ligatures[u]=l + for u,v in next,l do + l[u]={ ligature=v.char } + end + c.ligatures=nil + end + if k then + kerns[u]=k + for u,v in next,k do + k[u]=v + end + c.kerns=nil + end + end + for u,l in next,ligatures do + for k,v in next,l do + local vl=v.ligature + local dl=ligatures[vl] + if dl then + for kk,vv in next,dl do + v[kk]=vv + end + end + end + end + local features={ + gpos={}, + gsub={}, + } + local sequences={ + } + if next(ligatures) then + features.gsub.liga=everywhere + data.properties.hasligatures=true + sequences[#sequences+1]={ + features={ + liga=everywhere, + }, + flags=noflags, + name="s_s_0", + nofsteps=1, + order={ "liga" }, + type="gsub_ligature", + steps={ + { + coverage=ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern=everywhere + data.properties.haskerns=true + sequences[#sequences+1]={ + features={ + kern=everywhere, + }, + flags=noflags, + name="p_s_0", + nofsteps=1, + order={ "kern" }, + type="gpos_pair", + steps={ + { + format="kern", + coverage=kerns, + }, + }, + } + end + data.resources.features=features + data.resources.sequences=sequences + data.shared.resources=data.shared.resources or resources + end +end +registertfmfeature { + name="mode", + description="mode", + initializers={ + base=otf.modeinitializer, + node=otf.modeinitializer, + } +} +registertfmfeature { + name="features", + description="features", + default=true, + initializers={ + base=otf.basemodeinitializer, + node=otf.nodemodeinitializer, + }, + processors={ + node=otf.featuresprocessor, + } +} + +end -- closure + +do -- begin closure to overcome local limits and interference + if not modules then modules={} end modules ['font-lua']={ version=1.001, comment="companion to font-ini.mkiv", @@ -24582,10 +25015,11 @@ if not modules then modules={} end modules ['font-def']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub +local lower,gsub=string.lower,string.gsub local tostring,next=tostring,next local lpegmatch=lpeg.match local suffixonly,removesuffix=file.suffix,file.removesuffix +local formatters=string.formatters local allocate=utilities.storage.allocate local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end) local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end) @@ -24746,7 +25180,7 @@ function definers.applypostprocessors(tfmdata) local extrahash=postprocessors[i](tfmdata) if type(extrahash)=="string" and extrahash~="" then extrahash=gsub(lower(extrahash),"[^a-z]","-") - properties.fullname=format("%s-%s",properties.fullname,extrahash) + properties.fullname=formatters["%s-%s"](properties.fullname,extrahash) end end end |