diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua | 2734 |
1 files changed, 1320 insertions, 1414 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua index 0a14e6082d3..0c9bfcc380f 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/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 : 10/18/18 00:07:52 +-- merge date : 12/19/18 19:22:22 do -- begin closure to overcome local limits and interference @@ -554,64 +554,6 @@ function lpeg.counter(pattern,action) return function(str) n=0;lpegmatch(pattern,str);return n end end end -utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters -local utfgmatch=utf and utf.gmatch -local utfchar=utf and utf.char -lpeg.UP=lpeg.P -if utfcharacters then - function lpeg.US(str) - local p=P(false) - for uc in utfcharacters(str) do - p=p+P(uc) - end - return p - end -elseif utfgmatch then - function lpeg.US(str) - local p=P(false) - for uc in utfgmatch(str,".") do - p=p+P(uc) - end - return p - end -else - function lpeg.US(str) - local p=P(false) - local f=function(uc) - p=p+P(uc) - end - lpegmatch((utf8char/f)^0,str) - return p - end -end -local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more) - local first,last - if type(str)=="number" then - first=str - last=more or first - else - first,last=lpegmatch(range,str) - if not last then - return P(str) - end - end - if first==last then - return P(str) - elseif utfchar and (last-first<8) then - local p=P(false) - for i=first,last do - p=p+P(utfchar(i)) - end - return p - else - local f=function(b) - return b>=first and b<=last - end - return utf8byte/f - end -end function lpeg.is_lpeg(p) return p and lpegtype(p)=="pattern" end @@ -1107,7 +1049,6 @@ local table,string=table,string local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable -local getinfo=debug.getinfo local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper @@ -1669,20 +1610,23 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tv=="function" then if functions then - local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=load(%q),",depth,k,f)) + local getinfo=debug and debug.getinfo + if getinfo then + local f=getinfo(v).what=="C" and dump(dummy) or dump(v) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + 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 - handle(format("%s [%s]=load(%q),",depth,k,f)) + handle(format("%s [%q]=load(%q),",depth,k,f)) 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 - handle(format("%s [%q]=load(%q),",depth,k,f)) end end else @@ -3088,699 +3032,6 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['l-unicode']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -utf=utf or (unicode and unicode.utf8) or {} -utf.characters=utf.characters or string.utfcharacters -utf.values=utf.values or string.utfvalues -local type=type -local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch -local concat=table.concat -local P,C,R,Cs,Ct,Cmt,Cc,Carg,Cp=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Ct,lpeg.Cmt,lpeg.Cc,lpeg.Carg,lpeg.Cp -local lpegmatch=lpeg.match -local patterns=lpeg.patterns -local tabletopattern=lpeg.utfchartabletopattern -local bytepairs=string.bytepairs -local finder=lpeg.finder -local replacer=lpeg.replacer -local utfvalues=utf.values -local utfgmatch=utf.gmatch -local p_utftype=patterns.utftype -local p_utfstricttype=patterns.utfstricttype -local p_utfoffset=patterns.utfoffset -local p_utf8char=patterns.utf8character -local p_utf8byte=patterns.utf8byte -local p_utfbom=patterns.utfbom -local p_newline=patterns.newline -local p_whitespace=patterns.whitespace -if not unicode then - unicode={ utf=utf } -end -if not utf.char then - utf.char=string.utfcharacter or (utf8 and utf8.char) - if not utf.char then - local char=string.char - if bit32 then - local rshift=bit32.rshift - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+rshift(n,6), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+rshift(n,12), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+rshift(n,18), - 0x80+(rshift(n,12)%0x40), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end - else - local floor=math.floor - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+floor(n/0x40), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+floor(n/0x1000), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+floor(n/0x40000), - 0x80+(floor(n/0x1000)%0x40), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end - end - end -end -if not utf.byte then - utf.byte=string.utfvalue or (utf8 and utf8.codepoint) - if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - end - end -end -local utfchar,utfbyte=utf.char,utf.byte -function utf.filetype(data) - return data and lpegmatch(p_utftype,data) or "unknown" -end -local toentities=Cs ( - ( - patterns.utf8one+( - patterns.utf8two+patterns.utf8three+patterns.utf8four - )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end - )^0 -) -patterns.toentities=toentities -function utf.toentities(str) - return lpegmatch(toentities,str) -end -local one=P(1) -local two=C(1)*C(1) -local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1) -local pattern=P("\254\255")*Cs(( - four/function(a,b,c,d) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(a,b) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 )+P("\255\254")*Cs(( - four/function(b,a,d,c) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(b,a) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 ) -function string.toutf(s) - return lpegmatch(pattern,s) or s -end -local validatedutf=Cs ( - ( - patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" - )^0 -) -patterns.validatedutf=validatedutf -function utf.is_valid(str) - return type(str)=="string" and lpegmatch(validatedutf,str) or false -end -if not utf.len then - utf.len=string.utflength or (utf8 and utf8.len) - if not utf.len then - local n,f=0,1 - local utfcharcounter=patterns.utfbom^-1*Cmt ( - Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, - function(_,t,d) - n=n+(t-f)/d - f=t - return true - end - )^0 - function utf.len(str) - n,f=0,1 - lpegmatch(utfcharcounter,str or "") - return n - end - end -end -utf.length=utf.len -if not utf.sub then - local utflength=utf.length - local b,e,n,first,last=0,0,0,0,0 - local function slide_zero(s,p) - n=n+1 - if n>=last then - e=p-1 - else - return p - end - end - local function slide_one(s,p) - n=n+1 - if n==first then - b=p - end - if n>=last then - e=p-1 - else - return p - end - end - local function slide_two(s,p) - n=n+1 - if n==first then - b=p - else - return true - end - end - local pattern_zero=Cmt(p_utf8char,slide_zero)^0 - local pattern_one=Cmt(p_utf8char,slide_one )^0 - local pattern_two=Cmt(p_utf8char,slide_two )^0 - local pattern_first=C(patterns.utf8character) - function utf.sub(str,start,stop) - if not start then - return str - end - if start==0 then - start=1 - end - if not stop then - if start<0 then - local l=utflength(str) - start=l+start - else - start=start-1 - end - b,n,first=0,0,start - lpegmatch(pattern_two,str) - if n>=first then - return sub(str,b) - else - return "" - end - end - if start<0 or stop<0 then - local l=utf.length(str) - if start<0 then - start=l+start - if start<=0 then - start=1 - else - start=start+1 - end - end - if stop<0 then - stop=l+stop - if stop==0 then - stop=1 - else - stop=stop+1 - end - end - end - if start==1 and stop==1 then - return lpegmatch(pattern_first,str) or "" - elseif start>stop then - return "" - elseif start>1 then - b,e,n,first,last=0,0,0,start-1,stop - lpegmatch(pattern_one,str) - if n>=first and e==0 then - e=#str - end - return sub(str,b,e) - else - b,e,n,last=1,0,0,stop - lpegmatch(pattern_zero,str) - if e==0 then - e=#str - end - return sub(str,b,e) - end - end -end -function utf.remapper(mapping,option,action) - local variant=type(mapping) - if variant=="table" then - action=action or mapping - if option=="dynamic" then - local pattern=false - table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) - return function(str) - if not str or str=="" then - return "" - else - if not pattern then - pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8char)^0) - else - local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern - end - elseif variant=="function" then - if option=="pattern" then - return Cs((p_utf8char/mapping+p_utf8char)^0) - else - local pattern=Cs((p_utf8char/mapping+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern - end - else - return function(str) - return str or "" - end - end -end -function utf.replacer(t) - local r=replacer(t,false,false,true) - return function(str) - return lpegmatch(r,str) - end -end -function utf.subtituter(t) - local f=finder (t) - local r=replacer(t,false,false,true) - return function(str) - local i=lpegmatch(f,str) - if not i then - return str - elseif i>#str then - return str - else - return lpegmatch(r,str) - end - end -end -local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline) -local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0) -local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0) -local utfcharsplitter_raw=Ct(C(p_utf8char)^0) -patterns.utflinesplitter=utflinesplitter -function utf.splitlines(str) - return lpegmatch(utflinesplitter,str or "") -end -function utf.split(str,ignorewhitespace) - if ignorewhitespace then - return lpegmatch(utfcharsplitter_iws,str or "") - else - return lpegmatch(utfcharsplitter_ows,str or "") - end -end -function utf.totable(str) - return lpegmatch(utfcharsplitter_raw,str) -end -function utf.magic(f) - local str=f:read(4) or "" - local off=lpegmatch(p_utfoffset,str) - if off<4 then - f:seek('set',off) - end - return lpegmatch(p_utftype,str) -end -local utf16_to_utf8_be,utf16_to_utf8_le -local utf32_to_utf8_be,utf32_to_utf8_le -local utf_16_be_getbom=patterns.utfbom_16_be^-1 -local utf_16_le_getbom=patterns.utfbom_16_le^-1 -local utf_32_be_getbom=patterns.utfbom_32_be^-1 -local utf_32_le_getbom=patterns.utfbom_32_le^-1 -local utf_16_be_linesplitter=utf_16_be_getbom*lpeg.tsplitat(patterns.utf_16_be_nl) -local utf_16_le_linesplitter=utf_16_le_getbom*lpeg.tsplitat(patterns.utf_16_le_nl) -local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_nl) -local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl) -local more=0 -local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end -end -local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end -end -local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) -end -local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) -end -p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0) -p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0) -p_utf32_to_utf8_be=P(true)/function() more=0 end*utf_32_be_getbom*Cs(p_utf32_to_utf8_be^0) -p_utf32_to_utf8_le=P(true)/function() more=0 end*utf_32_le_getbom*Cs(p_utf32_to_utf8_le^0) -patterns.utf16_to_utf8_be=p_utf16_to_utf8_be -patterns.utf16_to_utf8_le=p_utf16_to_utf8_le -patterns.utf32_to_utf8_be=p_utf32_to_utf8_be -patterns.utf32_to_utf8_le=p_utf32_to_utf8_le -utf16_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_be,s) - else - return s - end -end -local utf16_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_be,s) - end - end - return t -end -utf16_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_le,s) - else - return s - end -end -local utf16_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_le,s) - end - end - return t -end -utf32_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_be,s) - else - return s - end -end -local utf32_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_be,s) - end - end - return t -end -utf32_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_le,s) - else - return s - end -end -local utf32_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_le,s) - end - end - return t -end -utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t -utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t -utf.utf32_to_utf8_le_t=utf32_to_utf8_le_t -utf.utf32_to_utf8_be_t=utf32_to_utf8_be_t -utf.utf16_to_utf8_le=utf16_to_utf8_le -utf.utf16_to_utf8_be=utf16_to_utf8_be -utf.utf32_to_utf8_le=utf32_to_utf8_le -utf.utf32_to_utf8_be=utf32_to_utf8_be -function utf.utf8_to_utf8_t(t) - return type(t)=="string" and lpegmatch(utflinesplitter,t) or t -end -function utf.utf16_to_utf8_t(t,endian) - return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t -end -function utf.utf32_to_utf8_t(t,endian) - return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t -end -local function little(b) - if b<0x10000 then - return char(b%256,rshift(b,8)) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) - end -end -local function big(b) - if b<0x10000 then - return char(rshift(b,8),b%256) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) - end -end -local l_remap=Cs((p_utf8byte/little+P(1)/"")^0) -local b_remap=Cs((p_utf8byte/big+P(1)/"")^0) -local function utf8_to_utf16_be(str,nobom) - if nobom then - return lpegmatch(b_remap,str) - else - return char(254,255)..lpegmatch(b_remap,str) - end -end -local function utf8_to_utf16_le(str,nobom) - if nobom then - return lpegmatch(l_remap,str) - else - return char(255,254)..lpegmatch(l_remap,str) - end -end -utf.utf8_to_utf16_be=utf8_to_utf16_be -utf.utf8_to_utf16_le=utf8_to_utf16_le -function utf.utf8_to_utf16(str,littleendian,nobom) - if littleendian then - return utf8_to_utf16_le(str,nobom) - else - return utf8_to_utf16_be(str,nobom) - end -end -local pattern=Cs ( - (p_utf8byte/function(unicode ) return format("0x%04X",unicode) end)*(p_utf8byte*Carg(1)/function(unicode,separator) return format("%s0x%04X",separator,unicode) end)^0 -) -function utf.tocodes(str,separator) - return lpegmatch(pattern,str,1,separator or " ") -end -function utf.ustring(s) - return format("U+%05X",type(s)=="number" and s or utfbyte(s)) -end -function utf.xstring(s) - return format("0x%05X",type(s)=="number" and s or utfbyte(s)) -end -function utf.toeight(str) - if not str or str=="" then - return nil - end - local utftype=lpegmatch(p_utfstricttype,str) - if utftype=="utf-8" then - return sub(str,4) - elseif utftype=="utf-16-be" then - return utf16_to_utf8_be(str) - elseif utftype=="utf-16-le" then - return utf16_to_utf8_le(str) - else - return str - end -end -local p_nany=p_utf8char/"" -if utfgmatch then - function utf.count(str,what) - if type(what)=="string" then - local n=0 - for _ in utfgmatch(str,what) do - n=n+1 - end - return n - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -else - local cache={} - function utf.count(str,what) - if type(what)=="string" then - local p=cache[what] - if not p then - p=Cs((P(what)/" "+p_nany)^0) - cache[p]=p - end - return #lpegmatch(p,str) - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -end -if not utf.characters then - function utf.characters(str) - return gmatch(str,".[\128-\191]*") - end - string.utfcharacters=utf.characters -end -if not utf.values then - local find=string.find - local dummy=function() - end - function utf.values(str) - local n=#str - if n==0 then - return dummy - elseif n==1 then - return function() return utfbyte(str) end - else - local p=1 - return function() - local b,e=find(str,".[\128-\191]*",p) - if b then - p=e+1 - return utfbyte(sub(str,b,e)) - end - end - end - end - string.utfvalues=utf.values -end -function utf.chrlen(u) - return - (u<0x80 and 1) or - (u<0xE0 and 2) or - (u<0xF0 and 3) or - (u<0xF8 and 4) or - (u<0xFC and 5) or - (u<0xFE and 6) or 0 -end -if bit32 then - local extract=bit32.extract - local char=string.char - function unicode.toutf32string(n) - if n<=0xFF then - return - char(n).."\000\000\000" - elseif n<=0xFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" - elseif n<=0xFFFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" - else - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) - end - end -end -local len=utf.len -local rep=rep -function string.utfpadd(s,n) - if n and n~=0 then - local l=len(s) - if n>0 then - local d=n-l - if d>0 then - return rep(c or " ",d)..s - end - else - local d=- n-l - if d>0 then - return s..rep(c or " ",d) - end - end - end - return s -end - -end -- closure - -do -- begin closure to overcome local limits and interference - if not modules then modules={} end modules ['util-str']={ version=1.001, comment="companion to luat-lib.mkiv", @@ -4649,6 +3900,10 @@ function strings.newcollector() end end end +local f_16_16=formatters["%0.5N"] +function number.to16dot16(n) + return f_16_16(n/65536.0) +end end -- closure @@ -4661,6 +3916,7 @@ if not modules then modules={} end modules ['util-fil']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } +local tonumber=tonumber local byte=string.byte local char=string.char utilities=utilities or {} @@ -4819,17 +4075,17 @@ end function files.readfixed2(f) local a,b=byte(f:read(2),1,2) if a>=0x80 then - return (a-0x100)+b/0x100 + tonumber((a-0x100).."."..b) else - return (a )+b/0x100 + tonumber((a ).."."..b) end end function files.readfixed4(f) local a,b,c,d=byte(f:read(4),1,4) if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) else - return (0x100*a+b )+(0x100*c+d)/0x10000 + tonumber((0x100*a+b ).."."..(0x100*c+d)) end end if bit32 then @@ -4963,6 +4219,7 @@ local match,gmatch,gsub,lower=string.match,string.gmatch,string.gsub,string.lowe local formatters,split,format,dump=string.formatters,string.split,string.format,string.dump local loadfile,type=loadfile,type local setmetatable,getmetatable,collectgarbage=setmetatable,getmetatable,collectgarbage +local floor=math.floor local dummyfunction=function() end local dummyreporter=function(c) @@ -5273,6 +4530,59 @@ if arg then end end end +if not number.idiv then + function number.idiv(i,d) + return floor(i/d) + end +end +local u=unicode and unicode.utf8 +if u then + utf.lower=u.lower + utf.upper=u.upper + utf.char=u.char + utf.byte=u.byte + utf.len=u.len + if lpeg.setutfcasers then + lpeg.setutfcasers(u.lower,u.upper) + end + local bytepairs=string.bytepairs + local utfchar=utf.char + local concat=table.concat + function utf.utf16_to_utf8_be(s) + if not s then + return nil + elseif s=="" then + return "" + end + local result,r,more={},0,0 + for left,right in bytepairs(s) do + if right then + local now=256*left+right + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + r=r+1 + result[r]=utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + else + r=r+1 + result[r]=utfchar(now) + end + end + end + return concat(result) + end + local characters=string.utfcharacters + function utf.split(str) + local t,n={},0 + for s in characters(str) do + n=n+1 + t[n]=s + end + return t + end +end end -- closure @@ -9839,9 +9149,9 @@ function constructors.scale(tfmdata,specification) constructors.aftercopyingcharacters(target,tfmdata) constructors.trytosharefont(target,tfmdata) local vfonts=target.fonts -if isvirtual or target.type=="virtual" or properties.virtualized then + if isvirtual or target.type=="virtual" or properties.virtualized then properties.virtualized=true -target.type="virtual" + target.type="virtual" if not vfonts or #vfonts==0 then target.fonts={ { id=0 } } end @@ -9921,23 +9231,20 @@ function constructors.finalize(tfmdata) if not properties.virtualized then properties.virtualized=tfmdata.type=="virtual" end - if not tfmdata.properties then - tfmdata.properties={ - fontname=tfmdata.fontname, - filename=tfmdata.filename, - fullname=tfmdata.fullname, - name=tfmdata.name, - psname=tfmdata.psname, - encodingbytes=tfmdata.encodingbytes or 1, - embedding=tfmdata.embedding or "subset", - tounicode=tfmdata.tounicode or 1, - cidinfo=tfmdata.cidinfo or nil, - format=tfmdata.format or "type1", - direction=tfmdata.direction or 0, - writingmode=tfmdata.writingmode or "horizontal", - identity=tfmdata.identity or "horizontal", - } - end + properties.fontname=tfmdata.fontname + properties.filename=tfmdata.filename + properties.fullname=tfmdata.fullname + properties.name=tfmdata.name + properties.psname=tfmdata.psname + properties.encodingbytes=tfmdata.encodingbytes or 1 + properties.embedding=tfmdata.embedding or "subset" + properties.tounicode=tfmdata.tounicode or 1 + properties.cidinfo=tfmdata.cidinfo or nil + properties.format=tfmdata.format or "type1" + properties.direction=tfmdata.direction or 0 + properties.writingmode=tfmdata.writingmode or "horizontal" + properties.identity=tfmdata.identity or "horizontal" + properties.usedbitmap=tfmdata.usedbitmap if not tfmdata.resources then tfmdata.resources={} end @@ -11164,7 +10471,7 @@ if not modules then modules={} end modules ['font-vfc']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local select=select +local select,type=select,type local insert=table.insert local fonts=fonts local helpers=fonts.helpers @@ -11176,7 +10483,7 @@ local dummy={ "comment" } function helpers.prependcommands(commands,...) insert(commands,1,push) for i=select("#",...),1,-1 do - local s=select(i,...) + local s=(select(i,...)) if s then insert(commands,1,s) end @@ -11188,7 +10495,29 @@ function helpers.appendcommands(commands,...) insert(commands,1,push) insert(commands,pop) for i=1,select("#",...) do - local s=select(i,...) + local s=(select(i,...)) + if s then + insert(commands,s) + end + end + return commands +end +function helpers.prependcommandtable(commands,t) + insert(commands,1,push) + for i=#t,1,-1 do + local s=t[i] + if s then + insert(commands,1,s) + end + end + insert(commands,pop) + return commands +end +function helpers.appendcommandtable(commands,t) + insert(commands,1,push) + insert(commands,pop) + for i=1,#t do + local s=t[i] if s then insert(commands,s) end @@ -11244,6 +10573,7 @@ if not modules then modules={} end modules ['font-otr']={ } local next,type,tonumber=next,type,tonumber local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub +local fullstrip=string.fullstrip local floor,round=math.floor,math.round local P,R,S,C,Cs,Cc,Ct,Carg,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg,lpeg.Cmt local lpegmatch=lpeg.match @@ -11520,19 +10850,29 @@ local helpers={} readers.helpers=helpers local function gotodatatable(f,fontdata,tag,criterium) if criterium and f then - local datatable=fontdata.tables[tag] - if datatable then - local tableoffset=datatable.offset - setposition(f,tableoffset) - return tableoffset + local tables=fontdata.tables + if tables then + local datatable=tables[tag] + if datatable then + local tableoffset=datatable.offset + setposition(f,tableoffset) + return tableoffset + end + else + report("no tables") end end end local function reportskippedtable(f,fontdata,tag,criterium) if criterium and f then - local datatable=fontdata.tables[tag] - if datatable then - report("loading of table %a skipped",tag) + local tables=fontdata.tables + if tables then + local datatable=tables[tag] + if datatable then + report("loading of table %a skipped",tag) + end + else + report("no tables") end end end @@ -11556,6 +10896,15 @@ local platformnames={ typographicsubfamily=true, compatiblefullname=true, } +local platformextras={ + uniqueid=true, + version=true, + copyright=true, + license=true, + licenseurl=true, + manufacturer=true, + vendorurl=true, +} function readers.name(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"name",true) if tableoffset then @@ -11608,6 +10957,17 @@ function readers.name(f,fontdata,specification) local names={} local done={} local extras={} + local function decoded(platform,encoding,content) + local decoder=decoders[platform] + if decoder then + decoder=decoder[encoding] + end + if decoder then + return decoder(content) + else + return content + end + end local function filter(platform,e,l) local namelist=namelists[platform] for i=1,#namelist do @@ -11619,14 +10979,7 @@ function readers.name(f,fontdata,specification) local language=name.language if (not e or encoding==e) and (not l or language==l) then setposition(f,name.offset) - local content=readstring(f,name.length) - local decoder=decoders[platform] - if decoder then - decoder=decoder[encoding] - end - if decoder then - content=decoder(content) - end + local content=decoded(platform,encoding,readstring(f,name.length)) if nametag then names[nametag]={ content=content, @@ -11650,22 +11003,15 @@ function readers.name(f,fontdata,specification) fontdata.extras=extras if specification.platformnames then local collected={} + local platformextras=specification.platformextras and platformextras for platform,namelist in next,namelists do local filtered=false for i=1,#namelist do local entry=namelist[i] local name=entry.name - if platformnames[name] then + if platformnames[name] or (platformextras and platformextras[name]) then setposition(f,entry.offset) - local content=readstring(f,entry.length) - local encoding=entry.encoding - local decoder=decoders[platform] - if decoder then - decoder=decoder[encoding] - end - if decoder then - content=decoder(content) - end + local content=decoded(platform,entry.encoding,readstring(f,entry.length)) if filtered then filtered[name]=content else @@ -11730,7 +11076,7 @@ readers["os/2"]=function(f,fontdata) if version>=1 then windowsmetrics.codepageranges={ readulong(f),readulong(f) } end - if version>=3 then + if version>=2 then windowsmetrics.xheight=readshort(f) windowsmetrics.capheight=readshort(f) windowsmetrics.defaultchar=readushort(f) @@ -11748,10 +11094,13 @@ end readers.head=function(f,fontdata) local tableoffset=gotodatatable(f,fontdata,"head",true) if tableoffset then + local version=readulong(f) + local fontversion=readulong(f) local fontheader={ - version=readfixed(f), - revision=readfixed(f), - checksum=readulong(f), + version=version, + fontversion=number.to16dot16(fontversion), + fontversionnumber=fontversion, + checksum=readushort(f)*0x10000+readushort(f), magic=readulong(f), flags=readushort(f), units=readushort(f), @@ -11777,7 +11126,7 @@ readers.hhea=function(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details) if tableoffset then fontdata.horizontalheader={ - version=readfixed(f), + version=readulong(f), ascender=readfword(f), descender=readfword(f), linegap=readfword(f), @@ -11805,7 +11154,7 @@ readers.vhea=function(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details) if tableoffset then fontdata.verticalheader={ - version=readfixed(f), + version=readulong(f), ascender=readfword(f), descender=readfword(f), linegap=readfword(f), @@ -11832,15 +11181,15 @@ end readers.maxp=function(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"maxp",specification.details) if tableoffset then - local version=readfixed(f) + local version=readulong(f) local nofglyphs=readushort(f) fontdata.nofglyphs=nofglyphs - if version==0.5 then + if version==0x00005000 then fontdata.maximumprofile={ version=version, nofglyphs=nofglyphs, } - elseif version==1.0 then + elseif version==0x00010000 then fontdata.maximumprofile={ version=version, nofglyphs=nofglyphs, @@ -11877,7 +11226,7 @@ readers.hmtx=function(f,fontdata,specification) local leftsidebearing=0 for i=0,nofmetrics-1 do local glyph=glyphs[i] - width=readshort(f) + width=readshort(f) leftsidebearing=readshort(f) if width~=0 then glyph.width=width @@ -11923,7 +11272,7 @@ end readers.post=function(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"post",true) if tableoffset then - local version=readfixed(f) + local version=readulong(f) fontdata.postscript={ version=version, italicangle=round(1000*readfixed(f))/1000, @@ -11936,11 +11285,11 @@ readers.post=function(f,fontdata,specification) maxmemtype1=readulong(f), } if not specification.glyphs then - elseif version==1.0 then + elseif version==0x00010000 then for index=0,#standardromanencoding do glyphs[index].name=standardromanencoding[index] end - elseif version==2.0 then + elseif version==0x00020000 then local glyphs=fontdata.glyphs local nofglyphs=readushort(f) local indices={} @@ -11971,8 +11320,6 @@ readers.post=function(f,fontdata,specification) end end end - elseif version==2.5 then - elseif version==3.0 then end else fontdata.postscript={} @@ -12529,14 +11876,16 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst designsize=fontdata.designsize, minsize=fontdata.minsize, maxsize=fontdata.maxsize, + boundingbox=fontheader and { fontheader.xmin or 0,fontheader.ymin or 0,fontheader.xmax or 0,fontheader.ymax or 0 } or nil, monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced", averagewidth=metrics.averagewidth, xheight=metrics.xheight, - capheight=metrics.capheight, + capheight=metrics.capheight or fontdata.maxy, ascender=metrics.typoascender, descender=metrics.typodescender, platformnames=platformnames or nil, instancenames=instancenames or nil, + tableoffsets=fontdata.tableoffsets, } if metricstoo then local keys={ @@ -12594,7 +11943,7 @@ local function loadtables(f,specification,offset) } for i=1,fontdata.noftables do local tag=lower(stripstring(readstring(f,4))) - local checksum=readulong(f) + local checksum=readushort(f)*0x10000+readushort(f) local offset=readulong(f) local length=readulong(f) if offset+length>filesize then @@ -12612,7 +11961,7 @@ local function loadtables(f,specification,offset) else fontdata.format="truetype" end - return fontdata + return fontdata,tables end local function prepareglyps(fontdata) local glyphs=setmetatableindex(function(t,k) @@ -12633,7 +11982,7 @@ local function readtable(tag,f,fontdata,specification,...) end local variablefonts_supported=(context and true) or (logs and logs.application and true) or false local function readdata(f,offset,specification) - local fontdata=loadtables(f,specification,offset) + local fontdata,tables=loadtables(f,specification,offset) if specification.glyphs then prepareglyps(fontdata) end @@ -12743,9 +12092,18 @@ local function readdata(f,offset,specification) readtable("gpos",f,fontdata,specification) readtable("math",f,fontdata,specification) fontdata.locations=nil - fontdata.tables=nil fontdata.cidmaps=nil fontdata.dictionaries=nil + if specification.tableoffsets then + fontdata.tableoffsets=tables + setmetatableindex(tables,{ + version=fontdata.version, + noftables=fontdata.noftables, + searchrange=fontdata.searchrange, + entryselector=fontdata.entryselector, + rangeshift=fontdata.rangeshift, + }) + end return fontdata end local function loadfontdata(specification) @@ -12849,7 +12207,7 @@ local function loadfont(specification,n,instance) specification.instance=specification.instance or instance end local function message(str) - report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback()) + report("fatal error in file %a: %s\n%s",specification.filename,str,debug and debug.traceback()) end local ok,result=xpcall(loadfontdata,message,specification) if ok then @@ -12871,12 +12229,25 @@ function readers.loadshapes(filename,n,instance,streams) v.index=nil v.math=nil end + local names=fontdata.names + if names then + for k,v in next,names do + names[k]=fullstrip(v.content) + end + end end return fontdata and { filename=filename, format=fontdata.format, glyphs=fontdata.glyphs, units=fontdata.fontheader.units, + cffinfo=fontdata.cffinfo, + fontheader=fontdata.fontheader, + horizontalheader=fontdata.horizontalheader, + verticalheader=fontdata.verticalheader, + maximumprofile=fontdata.maximumprofile, + names=fontdata.names, + postscript=fontdata.postscript, } or { filename=filename, format="unknown", @@ -12928,7 +12299,7 @@ function readers.loadfont(filename,n,instance) mathconstants=fontdata.mathconstants, colorpalettes=fontdata.colorpalettes, svgshapes=fontdata.svgshapes, - sbixshapes=fontdata.sbixshapes, + pngshapes=fontdata.pngshapes, variabledata=fontdata.variabledata, foundtables=fontdata.foundtables, }, @@ -12940,10 +12311,12 @@ function readers.getinfo(filename,specification) local platformnames=false local rawfamilynames=false local instancenames=true + local tableoffsets=false if type(specification)=="table" then subfont=tonumber(specification.subfont) platformnames=specification.platformnames rawfamilynames=specification.rawfamilynames + tableoffsets=specification.tableoffsets else subfont=tonumber(specification) end @@ -12952,6 +12325,7 @@ function readers.getinfo(filename,specification) details=true, platformnames=platformnames, instancenames=true, + tableoffsets=tableoffsets, } if fontdata then local subfonts=fontdata.subfonts @@ -14219,7 +13593,7 @@ if not modules then modules={} end modules ['font-cff']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local next,type,tonumber=next,type,tonumber +local next,type,tonumber,rawget=next,type,tonumber,rawget local byte,char,gmatch=string.byte,string.char,string.gmatch local concat,remove,unpack=table.concat,table.remove,table.unpack local floor,abs,round,ceil,min,max=math.floor,math.abs,math.round,math.ceil,math.min,math.max @@ -14227,6 +13601,8 @@ local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct local lpegmatch=lpeg.match local formatters=string.formatters local bytetable=string.bytetable +local idiv=number.idiv +local rshift,band,extract=bit32.rshift,bit32.band,bit32.extract local readers=fonts.handlers.otf.readers local streamreader=readers.streamreader local readstring=streamreader.readstring @@ -14421,8 +13797,25 @@ do end+P("\05")/function() result.fontbbox={ unpack(stack,1,4) } top=0 - end -+P("\13")/function() + end+P("\06")/function() + result.bluevalues={ unpack(stack,1,top) } + top=0 + end+P("\07")/function() + result.otherblues={ unpack(stack,1,top) } + top=0 + end+P("\08")/function() + result.familyblues={ unpack(stack,1,top) } + top=0 + end+P("\09")/function() + result.familyotherblues={ unpack(stack,1,top) } + top=0 + end+P("\10")/function() + result.strhw=stack[top] + top=0 + end+P("\11")/function() + result.strvw=stack[top] + top=0 + end+P("\13")/function() result.uniqueid=stack[top] top=0 end+P("\14")/function() @@ -14488,6 +13881,21 @@ do end+P("\08")/function() result.strokewidth=stack[top] top=0 + end+P("\09")/function() + result.bluescale=stack[top] + top=0 + end+P("\10")/function() + result.bluesnap=stack[top] + top=0 + end+P("\11")/function() + result.bluefuzz=stack[top] + top=0 + end+P("\12")/function() + result.stemsnaph={ unpack(stack,1,top) } + top=0 + end+P("\13")/function() + result.stemsnapv={ unpack(stack,1,top) } + top=0 end+P("\20")/function() result.syntheticbase=stack[top] top=0 @@ -14531,24 +13939,24 @@ do top=0 end ) - local p_last=P("\x0F")/"0"+P("\x1F")/"1"+P("\x2F")/"2"+P("\x3F")/"3"+P("\x4F")/"4"+P("\x5F")/"5"+P("\x6F")/"6"+P("\x7F")/"7"+P("\x8F")/"8"+P("\x9F")/"9"+P("\xAF")/""+P("\xBF")/""+P("\xCF")/""+P("\xDF")/""+P("\xEF")/""+R("\xF0\xFF")/"" local remap={ ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0", - ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="0.",["\x1B"]="0E",["\x1C"]="0E-",["\x1D"]="0",["\x1E"]="0-",["\x1F"]="0", - ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="0.",["\x2B"]="0E",["\x2C"]="0E-",["\x2D"]="0",["\x2E"]="0-",["\x2F"]="0", - ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="0.",["\x3B"]="0E",["\x3C"]="0E-",["\x3D"]="0",["\x3E"]="0-",["\x3F"]="0", - ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="0.",["\x4B"]="0E",["\x4C"]="0E-",["\x4D"]="0",["\x4E"]="0-",["\x4F"]="0", - ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="0.",["\x5B"]="0E",["\x5C"]="0E-",["\x5D"]="0",["\x5E"]="0-",["\x5F"]="0", - ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="0.",["\x6B"]="0E",["\x6C"]="0E-",["\x6D"]="0",["\x6E"]="0-",["\x6F"]="0", - ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="0.",["\x7B"]="0E",["\x7C"]="0E-",["\x7D"]="0",["\x7E"]="0-",["\x7F"]="0", - ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="0.",["\x8B"]="0E",["\x8C"]="0E-",["\x8D"]="0",["\x8E"]="0-",["\x8F"]="0", - ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="0.",["\x9B"]="0E",["\x9C"]="0E-",["\x9D"]="0",["\x9E"]="0-",["\x9F"]="0", + ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1", + ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2", + ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="3.",["\x3B"]="3E",["\x3C"]="3E-",["\x3D"]="3",["\x3E"]="3-",["\x3F"]="3", + ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="4.",["\x4B"]="4E",["\x4C"]="4E-",["\x4D"]="4",["\x4E"]="4-",["\x4F"]="4", + ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="5.",["\x5B"]="5E",["\x5C"]="5E-",["\x5D"]="5",["\x5E"]="5-",["\x5F"]="5", + ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="6.",["\x6B"]="6E",["\x6C"]="6E-",["\x6D"]="6",["\x6E"]="6-",["\x6F"]="6", + ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="7.",["\x7B"]="7E",["\x7C"]="7E-",["\x7D"]="7",["\x7E"]="7-",["\x7F"]="7", + ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="8.",["\x8B"]="8E",["\x8C"]="8E-",["\x8D"]="8",["\x8E"]="8-",["\x8F"]="8", + ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="9.",["\x9B"]="9E",["\x9C"]="9E-",["\x9D"]="9",["\x9E"]="9-",["\x9F"]="9", ["\xA0"]=".0",["\xA1"]=".1",["\xA2"]=".2",["\xA3"]=".3",["\xA4"]=".4",["\xA5"]=".5",["\xA6"]=".6",["\xA7"]=".7",["\xA8"]=".8",["\xA9"]=".9",["\xAA"]="..",["\xAB"]=".E",["\xAC"]=".E-",["\xAD"]=".",["\xAE"]=".-",["\xAF"]=".", ["\xB0"]="E0",["\xB1"]="E1",["\xB2"]="E2",["\xB3"]="E3",["\xB4"]="E4",["\xB5"]="E5",["\xB6"]="E6",["\xB7"]="E7",["\xB8"]="E8",["\xB9"]="E9",["\xBA"]="E.",["\xBB"]="EE",["\xBC"]="EE-",["\xBD"]="E",["\xBE"]="E-",["\xBF"]="E", ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-", ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-", } - local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0+p_last)/function(n) + local p_last=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")+R("\xF0\xFF") + local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0*(P(1)/remap))/function(n) top=top+1 stack[top]=tonumber(n) or 0 end @@ -15169,7 +14577,7 @@ do if trace_charstrings then showstate("stem") end - stems=stems+top/2 + stems=stems+idiv(top,2) top=0 end local function getmask() @@ -15188,13 +14596,13 @@ do if trace_charstrings then showstate(operator==19 and "hintmark" or "cntrmask") end - stems=stems+top/2 + stems=stems+idiv(top,2) top=0 if stems==0 then elseif stems<=8 then return 1 else - return floor((stems+7)/8) + return idiv(stems+7,8) end end local function unsupported(t) @@ -15233,7 +14641,7 @@ do local function hsbw() if version==1 then if trace_charstrings then - showstate("dotsection") + showstate("hsbw") end width=stack[top] end @@ -15419,76 +14827,98 @@ do [036]=hflex1, [037]=flex1, } - local c_endchar=char(14) - local passon do - local rshift=bit32.rshift - local band=bit32.band - local round=math.round - local encode=table.setmetatableindex(function(t,i) - for i=-2048,-1130 do - t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) - end - for i=-1131,-108 do - local v=0xFB00-i-108 - t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF)) - end - for i=-107,107 do - t[i]=char(i+139) - end - for i=108,1131 do - local v=0xF700+i-108 - t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF)) - end - for i=1132,2048 do - t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) - end - return t[i] - end) - local function setvsindex() - local vsindex=stack[top] - updateregions(vsindex) - top=top-1 + local chars=setmetatableindex(function (t,k) + local v=char(k) + t[k]=v + return v + end) + local c_endchar=chars[14] + local encode={} + setmetatableindex(encode,function(t,i) + for i=-2048,-1130 do + t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) end - local function blend() - local n=stack[top] - top=top-1 - if not axis then - elseif n==1 then - top=top-nofregions - local v=stack[top] + for i=-1131,-108 do + local v=0xFB00-i-108 + t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF)) + end + for i=-107,107 do + t[i]=chars[i+139] + end + for i=108,1131 do + local v=0xF700+i-108 + t[i]=char(extract(v,8,8),extract(v,0,8)) + end + for i=1132,2048 do + t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + end + setmetatableindex(encode,function(t,k) + local r=round(k) + local v=rawget(t,r) + if v then + return v + end + local v1=floor(k) + local v2=floor((k-v1)*0x10000) + return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8)) + end) + return t[i] + end) + readers.cffencoder=encode + local function p_setvsindex() + local vsindex=stack[top] + updateregions(vsindex) + top=top-1 + end + local function p_blend() + local n=stack[top] + top=top-1 + if not axis then + elseif n==1 then + top=top-nofregions + local v=stack[top] + for r=1,nofregions do + v=v+stack[top+r]*factors[r] + end + stack[top]=round(v) + else + top=top-nofregions*n + local d=top + local k=top-n + for i=1,n do + k=k+1 + local v=stack[k] for r=1,nofregions do - v=v+stack[top+r]*factors[r] - end - stack[top]=round(v) - else - top=top-nofregions*n - local d=top - local k=top-n - for i=1,n do - k=k+1 - local v=stack[k] - for r=1,nofregions do - v=v+stack[d+r]*factors[r] - end - stack[k]=round(v) - d=d+nofregions + v=v+stack[d+r]*factors[r] end + stack[k]=round(v) + d=d+nofregions end end - passon=function(operation) - if operation==15 then - setvsindex() - elseif operation==16 then - blend() - else - for i=1,top do - r=r+1 - result[r]=encode[stack[i]] - end - r=r+1 - result[r]=char(operation) - top=0 - end + end + local function p_getstem() + local n=0 + if top%2~=0 then + n=1 + end + if top>n then + stems=stems+idiv(top-n,2) + end + end + local function p_getmask() + local n=0 + if top%2~=0 then + n=1 + end + if top>n then + stems=stems+idiv(top-n,2) + end + if stems==0 then + return 0 + elseif stems<=8 then + return 1 + else + return idiv(stems+7,8) end end local process @@ -15576,19 +15006,90 @@ do elseif t==12 then i=i+1 local t=tab[i] - local a=subactions[t] - if a then - a(t) + if justpass then + if t>=34 or t<=37 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + r=r+1;result[r]=chars[12] + r=r+1;result[r]=chars[t] + top=0 + else + local a=subactions[t] + if a then + a(t) + else + top=0 + end + end else - if trace_charstrings then - showvalue("<subaction>",t) + local a=subactions[t] + if a then + a(t) + else + if trace_charstrings then + showvalue("<subaction>",t) + end + top=0 end - top=0 end i=i+1 elseif justpass then - passon(t) - i=i+1 + if t==15 then + p_setvsindex() + i=i+1 + elseif t==16 then + local s=p_blend() or 0 + i=i+s+1 + elseif t==1 or t==3 or t==18 or operation==23 then + p_getstem() +if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] +else + top=0 +end + i=i+1 + elseif t==19 or t==20 then + local s=p_getmask() or 0 +if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] + for j=1,s do + i=i+1 + r=r+1;result[r]=chars[tab[i]] + end +else + i=i+s + top=0 +end + i=i+1 + elseif t==9 then + top=0 + i=i+1 + elseif t==13 then + local s=hsbw() or 0 + i=i+s+1 + else + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] + i=i+1 + end else local a=actions[t] if a then @@ -15609,18 +15110,20 @@ do end end local function setbias(globals,locals) - if version==1 then - return - false, - false - else local g,l=#globals,#locals return ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 - end end local function processshape(tab,index) + if not tab then + glyphs[index]={ + boundingbox={ 0,0,0,0 }, + width=0, + name=charset and charset[index] or nil, + } + return + end tab=bytetable(tab) x=0 y=0 @@ -15733,15 +15236,18 @@ do glyphs=glphs or {} globalbias,localbias=setbias(globals,locals) nominalwidth,defaultwidth=setwidths(dictionary.private) - startparsing(fontdata,data,streams) - for index=1,#charstrings do - processshape(charstrings[index],index-1) - charstrings[index]=nil + if charstrings then + startparsing(fontdata,data,streams) + for index=1,#charstrings do + processshape(charstrings[index],index-1) + end + stopparsing(fontdata,data) + else + report("no charstrings") end - stopparsing(fontdata,data) return glyphs end - parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion) + parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams) keepcurve=doshapes version=tversion strings=data.strings @@ -15750,6 +15256,7 @@ do charset=false vsindex=dictionary.vsindex or 0 glyphs=glphs or {} + justpass=streams==true globalbias,localbias=setbias(globals,locals) nominalwidth,defaultwidth=setwidths(dictionary.private) processshape(tab,index-1) @@ -15903,7 +15410,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) local format=readbyte(f) if format==1 then for i=0,nofglyphs do - local index=readbyte(i) + local index=readbyte(f) fdindex[i]=index if index>maxindex then maxindex=index @@ -15932,30 +15439,33 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) end if maxindex>=0 then local cidarray=cid.fdarray - setposition(f,header.offset+cidarray) - local dictionaries=readlengths(f) - for i=1,#dictionaries do - dictionaries[i]=readstring(f,dictionaries[i]) - end - parsedictionaries(data,dictionaries) - cid.dictionaries=dictionaries - readcidprivates(f,data) - for i=1,#dictionaries do - readlocals(f,data,dictionaries[i]) - end - startparsing(fontdata,data,streams) - for i=1,#charstrings do - parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version) - charstrings[i]=nil + if cidarray then + setposition(f,header.offset+cidarray) + local dictionaries=readlengths(f) + for i=1,#dictionaries do + dictionaries[i]=readstring(f,dictionaries[i]) + end + parsedictionaries(data,dictionaries) + cid.dictionaries=dictionaries + readcidprivates(f,data) + for i=1,#dictionaries do + readlocals(f,data,dictionaries[i]) + end + startparsing(fontdata,data,streams) + for i=1,#charstrings do + parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version,streams) + end + stopparsing(fontdata,data) + else + report("no cid array") end - stopparsing(fontdata,data) end end local gotodatatable=readers.helpers.gotodatatable local function cleanup(data,dictionaries) end function readers.cff(f,fontdata,specification) - local tableoffset=gotodatatable(f,fontdata,"cff",specification.details) + local tableoffset=gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs) if tableoffset then local header=readheader(f) if header.major~=1 then @@ -15976,14 +15486,16 @@ function readers.cff(f,fontdata,specification) parsedictionaries(data,dictionaries,"cff") local dic=dictionaries[1] local cid=dic.cid - fontdata.cffinfo={ - familynamename=dic.familyname, + local cffinfo={ + familyname=dic.familyname, fullname=dic.fullname, boundingbox=dic.boundingbox, weight=dic.weight, italicangle=dic.italicangle, underlineposition=dic.underlineposition, underlinethickness=dic.underlinethickness, + defaultwidth=dic.defaultwidthx, + nominalwidth=dic.nominalwidthx, monospaced=dic.monospaced, } fontdata.cidinfo=cid and { @@ -15991,12 +15503,30 @@ function readers.cff(f,fontdata,specification) ordering=cid.ordering, supplement=cid.supplement, } - if specification.glyphs then - local all=specification.shapes or false + fontdata.cffinfo=cffinfo + local all=specification.shapes or specification.streams or false + if specification.glyphs or all then if cid and cid.fdselect then - readfdselect(f,fontdata,data,glyphs,all,"cff") + readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams) else - readnoselect(f,fontdata,data,glyphs,all,"cff") + readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams) + end + end + local private=dic.private + if private then + local data=private.data + if type(data)=="table" then + cffinfo.defaultwidth=data.defaultwidth or cffinfo.defaultwidth + cffinfo.nominalwidth=data.nominalwidth or cffinfo.nominalwidth + cffinfo.bluevalues=data.bluevalues + cffinfo.otherblues=data.otherblues + cffinfo.familyblues=data.familyblues + cffinfo.familyotherblues=data.familyotherblues + cffinfo.bluescale=data.bluescale + cffinfo.blueshift=data.blueshift + cffinfo.bluefuzz=data.bluefuzz + cffinfo.stdhw=data.stdhw + cffinfo.stdvw=data.stdvw end end cleanup(data,dictionaries) @@ -16030,7 +15560,7 @@ function readers.cff2(f,fontdata,specification) end data.factors=specification.factors local cid=data.dictionaries[1].cid - local all=specification.shapes or false + local all=specification.shapes or specification.streams or false if cid and cid.fdselect then readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams) else @@ -16060,7 +15590,7 @@ function readers.cffcheck(filename) dictionaries=dictionaries, strings=strings, glyphs=glyphs, - nofglyphs=4, + nofglyphs=0, } parsedictionaries(data,dictionaries,"cff") local cid=data.dictionaries[1].cid @@ -16087,8 +15617,10 @@ if not modules then modules={} end modules ['font-ttf']={ local next,type,unpack=next,type,unpack local band,rshift=bit32.band,bit32.rshift local sqrt,round=math.sqrt,math.round -local char=string.char +local char,rep=string.char,string.rep local concat=table.concat +local idiv=number.idiv +local setmetatableindex=table.setmetatableindex local report=logs.reporter("otf reader","ttf") local trace_deltas=false local readers=fonts.handlers.otf.readers @@ -16153,22 +15685,41 @@ local function mergecomposites(glyphs,shapes) local yscale=matrix[4] local xoffset=matrix[5] local yoffset=matrix[6] - for i=1,#subpoints do - local p=subpoints[i] - local x=p[1] - local y=p[2] - nofpoints=nofpoints+1 - points[nofpoints]={ - xscale*x+xrotate*y+xoffset, - yscale*y+yrotate*x+yoffset, - p[3] - } + local count=#subpoints + if xscale==1 and yscale==1 and xrotate==0 and yrotate==0 then + for i=1,count do + local p=subpoints[i] + nofpoints=nofpoints+1 + points[nofpoints]={ + p[1]+xoffset, + p[2]+yoffset, + p[3] + } + end + else + for i=1,count do + local p=subpoints[i] + local x=p[1] + local y=p[2] + nofpoints=nofpoints+1 + points[nofpoints]={ + xscale*x+xrotate*y+xoffset, + yscale*y+yrotate*x+yoffset, + p[3] + } + end end - for i=1,#subcontours do + local subcount=#subcontours + if subcount==1 then nofcontours=nofcontours+1 - contours[nofcontours]=offset+subcontours[i] + contours[nofcontours]=offset+subcontours[1] + else + for i=1,#subcontours do + nofcontours=nofcontours+1 + contours[nofcontours]=offset+subcontours[i] + end end - offset=offset+#subpoints + offset=offset+count else report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex) end @@ -16178,7 +15729,7 @@ local function mergecomposites(glyphs,shapes) shape.components=nil return contours,points end - for index=1,#glyphs do + for index=0,#glyphs-1 do local shape=shapes[index] if shape then local components=shape.components @@ -16188,7 +15739,7 @@ local function mergecomposites(glyphs,shapes) end end end -local function readnothing(f,nofcontours) +local function readnothing(f) return { type="nothing", } @@ -16282,8 +15833,8 @@ local function applyaxis(glyph,shape,deltas,dowidth) end end local quadratic=false -local function contours2outlines_normal(glyphs,shapes) - for index=1,#glyphs do +local function contours2outlines_normal(glyphs,shapes) + for index=0,#glyphs-1 do local shape=shapes[index] if shape then local glyph=glyphs[index] @@ -16398,7 +15949,7 @@ local function contours2outlines_normal(glyphs,shapes) end end local function contours2outlines_shaped(glyphs,shapes,keepcurve) - for index=1,#glyphs do + for index=0,#glyphs-1 do local shape=shapes[index] if shape then local glyph=glyphs[index] @@ -16577,115 +16128,128 @@ local function toshort(n) end return char(band(rshift(n,8),0xFF),band(n,0xFF)) end +local chars=setmetatableindex(function(t,k) + for i=0,255 do local v=char(i) t[i]=v end return t[k] +end) local function repackpoints(glyphs,shapes) local noboundingbox={ 0,0,0,0 } local result={} - for index=1,#glyphs do + local xpoints={} + local ypoints={} + for index=0,#glyphs-1 do local shape=shapes[index] if shape then local r=0 local glyph=glyphs[index] - if false then - else - local contours=shape.contours - local nofcontours=contours and #contours or 0 - local boundingbox=glyph.boundingbox or noboundingbox - r=r+1 result[r]=toshort(nofcontours) - r=r+1 result[r]=toshort(boundingbox[1]) - r=r+1 result[r]=toshort(boundingbox[2]) - r=r+1 result[r]=toshort(boundingbox[3]) - r=r+1 result[r]=toshort(boundingbox[4]) - if nofcontours>0 then - for i=1,nofcontours do - r=r+1 result[r]=toshort(contours[i]-1) - end - r=r+1 result[r]=s_zero - local points=shape.points - local currentx=0 - local currenty=0 - local xpoints={} - local ypoints={} - local x=0 - local y=0 - local lastflag=nil - local nofflags=0 - for i=1,#points do - local pt=points[i] - local px=pt[1] - local py=pt[2] - local fl=pt[3] and 0x01 or 0x00 - if px==currentx then - fl=fl+0x10 + local contours=shape.contours + local nofcontours=contours and #contours or 0 + local boundingbox=glyph.boundingbox or noboundingbox + r=r+1 result[r]=toshort(nofcontours) + r=r+1 result[r]=toshort(boundingbox[1]) + r=r+1 result[r]=toshort(boundingbox[2]) + r=r+1 result[r]=toshort(boundingbox[3]) + r=r+1 result[r]=toshort(boundingbox[4]) + if nofcontours>0 then + for i=1,nofcontours do + r=r+1 result[r]=toshort(contours[i]-1) + end + r=r+1 result[r]=s_zero + local points=shape.points + local currentx=0 + local currenty=0 + local x=0 + local y=0 + local lastflag=nil + local nofflags=0 + for i=1,#points do + local pt=points[i] + local px=pt[1] + local py=pt[2] + local fl=pt[3] and 0x01 or 0x00 + if px==currentx then + fl=fl+0x10 + else + local dx=round(px-currentx) + x=x+1 + if dx<-255 or dx>255 then + xpoints[x]=toshort(dx) + elseif dx<0 then + fl=fl+0x02 + xpoints[x]=chars[-dx] + elseif dx>0 then + fl=fl+0x12 + xpoints[x]=chars[dx] else - local dx=round(px-currentx) - if dx<-255 or dx>255 then - x=x+1 xpoints[x]=toshort(dx) - elseif dx<0 then - fl=fl+0x02 - x=x+1 xpoints[x]=char(-dx) - elseif dx>0 then - fl=fl+0x12 - x=x+1 xpoints[x]=char(dx) - else - fl=fl+0x02 - x=x+1 xpoints[x]=c_zero - end + fl=fl+0x02 + xpoints[x]=c_zero end - if py==currenty then - fl=fl+0x20 + end + if py==currenty then + fl=fl+0x20 + else + local dy=round(py-currenty) + y=y+1 + if dy<-255 or dy>255 then + ypoints[y]=toshort(dy) + elseif dy<0 then + fl=fl+0x04 + ypoints[y]=chars[-dy] + elseif dy>0 then + fl=fl+0x24 + ypoints[y]=chars[dy] else - local dy=round(py-currenty) - if dy<-255 or dy>255 then - y=y+1 ypoints[y]=toshort(dy) - elseif dy<0 then - fl=fl+0x04 - y=y+1 ypoints[y]=char(-dy) - elseif dy>0 then - fl=fl+0x24 - y=y+1 ypoints[y]=char(dy) - else - fl=fl+0x04 - y=y+1 ypoints[y]=c_zero - end - end - currentx=px - currenty=py - if lastflag==fl then - nofflags=nofflags+1 - else - if nofflags==1 then - r=r+1 result[r]=char(lastflag) - elseif nofflags==2 then - r=r+1 result[r]=char(lastflag,lastflag) - elseif nofflags>2 then - lastflag=lastflag+0x08 - r=r+1 result[r]=char(lastflag,nofflags-1) - end - nofflags=1 - lastflag=fl + fl=fl+0x04 + ypoints[y]=c_zero end end - if nofflags==1 then - r=r+1 result[r]=char(lastflag) - elseif nofflags==2 then - r=r+1 result[r]=char(lastflag,lastflag) - elseif nofflags>2 then - lastflag=lastflag+0x08 - r=r+1 result[r]=char(lastflag,nofflags-1) - end - r=r+1 result[r]=concat(xpoints) - r=r+1 result[r]=concat(ypoints) + currentx=px + currenty=py + if lastflag==fl then + nofflags=nofflags+1 + else + if nofflags==1 then + r=r+1 result[r]=chars[lastflag] + elseif nofflags==2 then + r=r+1 result[r]=char(lastflag,lastflag) + elseif nofflags>2 then + lastflag=lastflag+0x08 + r=r+1 result[r]=char(lastflag,nofflags-1) + end + nofflags=1 + lastflag=fl + end + end + if nofflags==1 then + r=r+1 result[r]=chars[lastflag] + elseif nofflags==2 then + r=r+1 result[r]=char(lastflag,lastflag) + elseif nofflags>2 then + lastflag=lastflag+0x08 + r=r+1 result[r]=char(lastflag,nofflags-1) + end + r=r+1 result[r]=concat(xpoints,"",1,x) + r=r+1 result[r]=concat(ypoints,"",1,y) + end + local stream=concat(result,"",1,r) + local length=#stream + local padding=idiv(length+3,4)*4-length + if padding>0 then + if padding==1 then + padding="\0" + elseif padding==2 then + padding="\0\0" + else + padding="\0\0\0" end + padding=stream..padding end - glyph.stream=concat(result,"",1,r) - else + glyph.stream=stream end end end +local flags={} local function readglyph(f,nofcontours) local points={} - local instructions={} - local flags={} local contours={} for i=1,nofcontours do contours[i]=readshort(f)+1 @@ -16698,9 +16262,15 @@ local function readglyph(f,nofcontours) local flag=readbyte(f) flags[i]=flag if band(flag,0x08)~=0 then - for j=1,readbyte(f) do + local n=readbyte(f) + if n==1 then i=i+1 flags[i]=flag + else + for j=1,n do + i=i+1 + flags[i]=flag + end end end i=i+1 @@ -16708,15 +16278,13 @@ local function readglyph(f,nofcontours) local x=0 for i=1,nofpoints do local flag=flags[i] - local short=band(flag,0x02)~=0 - local same=band(flag,0x10)~=0 - if short then - if same then + if band(flag,0x02)~=0 then + if band(flag,0x10)~=0 then x=x+readbyte(f) else x=x-readbyte(f) end - elseif same then + elseif band(flag,0x10)~=0 then else x=x+readshort(f) end @@ -16725,15 +16293,13 @@ local function readglyph(f,nofcontours) local y=0 for i=1,nofpoints do local flag=flags[i] - local short=band(flag,0x04)~=0 - local same=band(flag,0x20)~=0 - if short then - if same then + if band(flag,0x04)~=0 then + if band(flag,0x20)~=0 then y=y+readbyte(f) else y=y-readbyte(f) end - elseif same then + elseif band(flag,0x20)~=0 then else y=y+readshort(f) end @@ -16816,7 +16382,7 @@ local function readcomposite(f) if band(flags,0x0100)~=0 then instructions=true end - if not band(flags,0x0020)~=0 then + if band(flags,0x0020)==0 then break end end @@ -16831,21 +16397,27 @@ function readers.loca(f,fontdata,specification) if datatable then local offset=fontdata.tables.glyf.offset local format=fontdata.fontheader.indextolocformat + local profile=fontdata.maximumprofile + local nofglyphs=profile and profile.nofglyphs local locations={} setposition(f,datatable.offset) if format==1 then - local nofglyphs=datatable.length/4-2 + if not nofglyphs then + nofglyphs=idiv(datatable.length,4)-1 + end for i=0,nofglyphs do locations[i]=offset+readulong(f) end fontdata.nofglyphs=nofglyphs else - local nofglyphs=datatable.length/2-2 + if not nofglyphs then + nofglyphs=idiv(datatable.length,2)-1 + end for i=0,nofglyphs do locations[i]=offset+readushort(f)*2 end - fontdata.nofglyphs=nofglyphs end + fontdata.nofglyphs=nofglyphs fontdata.locations=locations end end @@ -16860,15 +16432,16 @@ function readers.glyf(f,fontdata,specification) local filesize=fontdata.filesize local nothing={ 0,0,0,0 } local shapes={} - local loadshapes=specification.shapes or specification.instance - for index=0,nofglyphs do + local loadshapes=specification.shapes or specification.instance or specification.streams + for index=0,nofglyphs-1 do local location=locations[index] + local length=locations[index+1]-location if location>=filesize then report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1) fontdata.nofglyphs=index-1 fontdata.badfont=true break - elseif location>0 then + elseif length>0 then setposition(f,location) local nofcontours=readshort(f) glyphs[index].boundingbox={ @@ -16879,7 +16452,7 @@ function readers.glyf(f,fontdata,specification) } if not loadshapes then elseif nofcontours==0 then - shapes[index]=readnothing(f,nofcontours) + shapes[index]=readnothing(f) elseif nofcontours>0 then shapes[index]=readglyph(f,nofcontours) else @@ -16887,7 +16460,7 @@ function readers.glyf(f,fontdata,specification) end else if loadshapes then - shapes[index]={} + shapes[index]=readnothing(f) end glyphs[index].boundingbox=nothing end @@ -16904,7 +16477,13 @@ function readers.glyf(f,fontdata,specification) contours2outlines_shaped(glyphs,shapes,specification.shapes) end elseif specification.shapes then - contours2outlines_normal(glyphs,shapes) + if specification.streams then + repackpoints(glyphs,shapes) + else + contours2outlines_normal(glyphs,shapes) + end + elseif specification.streams then + repackpoints(glyphs,shapes) end end end @@ -17205,10 +16784,11 @@ local readers=fonts.handlers.otf.readers local streamreader=readers.streamreader local setposition=streamreader.setposition local getposition=streamreader.getposition -local readushort=streamreader.readcardinal2 -local readulong=streamreader.readcardinal4 +local readuinteger=streamreader.readcardinal1 +local readushort=streamreader.readcardinal2 +local readulong=streamreader.readcardinal4 local readinteger=streamreader.readinteger1 -local readshort=streamreader.readinteger2 +local readshort=streamreader.readinteger2 local readstring=streamreader.readstring local readtag=streamreader.readtag local readbytes=streamreader.readbytes @@ -17228,6 +16808,7 @@ directives.register("fonts.streamreader",function() streamreader=utilities.streams setposition=streamreader.setposition getposition=streamreader.getposition + readuinteger=streamreader.readcardinal1 readushort=streamreader.readcardinal2 readulong=streamreader.readcardinal4 readinteger=streamreader.readinteger1 @@ -19117,7 +18698,7 @@ do end local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder) setposition(f,variationsoffset) - local version=readulong(f) + local version=readulong(f) local nofrecords=readulong(f) local records={} for i=1,nofrecords do @@ -19824,59 +19405,269 @@ function readers.sbix(f,fontdata,specification) for i=1,nofstrikes do strikes[i]=readulong(f) end + local shapes={} + local done=0 + for i=1,nofstrikes do + local strikeoffset=strikes[i]+tableoffset + setposition(f,strikeoffset) + strikes[i]={ + ppem=readushort(f), + ppi=readushort(f), + offset=strikeoffset + } + end + sort(strikes,function(a,b) + if b.ppem==a.ppem then + return b.ppi<a.ppi + else + return b.ppem<a.ppem + end + end) + local glyphs={} + for i=1,nofstrikes do + local strike=strikes[i] + local strikeppem=strike.ppem + local strikeppi=strike.ppi + local strikeoffset=strike.offset + setposition(f,strikeoffset) + for i=0,nofglyphs do + glyphs[i]=readulong(f) + end + local glyphoffset=glyphs[0] + for i=0,nofglyphs-1 do + local nextoffset=glyphs[i+1] + if not shapes[i] then + local datasize=nextoffset-glyphoffset + if datasize>0 then + setposition(f,strikeoffset+glyphoffset) + shapes[i]={ + x=readshort(f), + y=readshort(f), + tag=readtag(f), + data=readstring(f,datasize-8), + ppem=strikeppem, + ppi=strikeppi, + } + done=done+1 + if done==nofglyphs then + break + end + end + end + glyphoffset=nextoffset + end + end + fontdata.pngshapes=shapes + end +end +do + local function getmetrics(f) + return { + ascender=readinteger(f), + descender=readinteger(f), + widthmax=readuinteger(f), + caretslopedumerator=readinteger(f), + caretslopedenominator=readinteger(f), + caretoffset=readinteger(f), + minorigin=readinteger(f), + minadvance=readinteger(f), + maxbefore=readinteger(f), + minafter=readinteger(f), + pad1=readinteger(f), + pad2=readinteger(f), + } + end + local function getbigmetrics(f) + return { + height=readuinteger(f), + width=readuinteger(f), + horiBearingX=readinteger(f), + horiBearingY=readinteger(f), + horiAdvance=readuinteger(f), + vertBearingX=readinteger(f), + vertBearingY=readinteger(f), + vertAdvance=readuinteger(f), + } + end + local function getsmallmetrics(f) + return { + height=readuinteger(f), + width=readuinteger(f), + bearingX=readinteger(f), + bearingY=readinteger(f), + advance=readuinteger(f), + } + end + function readers.cblc(f,fontdata,specification) + local ctdttableoffset=gotodatatable(f,fontdata,"cbdt",specification.glyphs) + if not ctdttableoffset then + return + end + local cblctableoffset=gotodatatable(f,fontdata,"cblc",specification.glyphs) + if cblctableoffset then + local majorversion=readushort(f) + local minorversion=readushort(f) + local nofsizetables=readulong(f) + local sizetables={} local shapes={} - local done=0 - for i=1,nofstrikes do - local strikeoffset=strikes[i]+tableoffset - setposition(f,strikeoffset) - strikes[i]={ - ppem=readushort(f), - ppi=readushort(f), - offset=strikeoffset + local subtables={} + for i=1,nofsizetables do + sizetables[i]={ + subtables=readulong(f), + indexsize=readulong(f), + nofsubtables=readulong(f), + colorref=readulong(f), + hormetrics=getmetrics(f), + vermetrics=getmetrics(f), + firstindex=readushort(f), + lastindex=readushort(f), + ppemx=readbyte(f), + ppemy=readbyte(f), + bitdepth=readbyte(f), + flags=readbyte(f), } end - sort(strikes,function(a,b) - if b.ppem==a.ppem then - return b.ppi<a.ppi + sort(sizetables,function(a,b) + if b.ppemx==a.ppemx then + return b.bitdepth<a.bitdepth else - return b.ppem<a.ppem + return b.ppemx<a.ppemx end end) - local glyphs={} - for i=1,nofstrikes do - local strike=strikes[i] - local strikeppem=strike.ppem - local strikeppi=strike.ppi - local strikeoffset=strike.offset - setposition(f,strikeoffset) - for i=0,nofglyphs do - glyphs[i]=readulong(f) - end - local glyphoffset=glyphs[0] - for i=0,nofglyphs-1 do - local nextoffset=glyphs[i+1] - if not shapes[i] then - local datasize=nextoffset-glyphoffset - if datasize>0 then - setposition(f,strikeoffset+glyphoffset) - shapes[i]={ - x=readshort(f), - y=readshort(f), - tag=readtag(f), - data=readstring(f,datasize-8), - ppem=strikeppem, - ppi=strikeppi, - } - done=done+1 - if done==nofglyphs then - break + for i=1,nofsizetables do + local s=sizetables[i] + local d=false + for j=s.firstindex,s.lastindex do + if not shapes[j] then + shapes[j]=i + d=true + end + end + if d then + s.used=true + end + end + for i=1,nofsizetables do + local s=sizetables[i] + if s.used then + local offset=s.subtables + setposition(f,cblctableoffset+offset) + for j=1,s.nofsubtables do + local firstindex=readushort(f) + local lastindex=readushort(f) + local tableoffset=readulong(f)+offset + for k=firstindex,lastindex do + if shapes[k]==i then + local s=subtables[tableoffset] + if not s then + s={ + firstindex=firstindex, + lastindex=lastindex, + } + subtables[tableoffset]=s + end + shapes[k]=s end end end - glyphoffset=nextoffset end end - fontdata.sbixshapes=shapes + for offset,subtable in sortedhash(subtables) do + local tabletype=readushort(f) + subtable.format=readushort(f) + local baseoffset=readulong(f)+ctdttableoffset + local offsets={} + local metrics=nil + if tabletype==1 then + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=readulong(f)+baseoffset + end + skipbytes(f,4) + elseif tabletype==2 then + local size=readulong(f) + local done=baseoffset + metrics=getbigmetrics(f) + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=done + done=done+size + end + elseif tabletype==3 then + local n=subtable.lastindex-subtable.firstindex+2 + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=readushort(f)+baseoffset + end + if math.odd(n) then + skipbytes(f,4) + else + skipbytes(f,2) + end + elseif tabletype==4 then + for i=1,readulong(f) do + offsets[readushort(f)]=readushort(f)+baseoffset + end + elseif tabletype==5 then + local size=readulong(f) + local done=baseoffset + metrics=getbigmetrics(f) + local n=readulong(f) + for i=1,n do + offsets[readushort(f)]=done + done=done+size + end + if math.odd(n) then + skipbytes(f,2) + end + else + return + end + subtable.offsets=offsets + subtable.metrics=metrics + end + local default={ width=0,height=0 } + local glyphs=fontdata.glyphs + for index,subtable in sortedhash(shapes) do + if type(subtable)=="table" then + local data=nil + local metrics=default + local format=subtable.format + local offset=subtable.offsets[index] + setposition(f,offset) + if format==17 then + metrics=getsmallmetrics(f) + data=readstring(f,readulong(f)) + elseif format==18 then + metrics=getbigmetrics(f) + data=readstring(f,readulong(f)) + elseif format==19 then + metrics=subtable.metrics + data=readstring(f,readulong(f)) + else + end + local x=metrics.width + local y=metrics.height + shapes[index]={ + x=x, + y=y, + data=data, + } + local glyph=glyphs[index] + if not glyph.boundingbox then + local width=glyph.width + local height=width*y/x + glyph.boundingbox={ 0,0,width,height } + end + else + shapes[index]={ + x=0, + y=0, + data="", + } + end + end + fontdata.pngshapes=shapes + end + end + function readers.cbdt(f,fontdata,specification) end end function readers.stat(f,fontdata,specification) @@ -19986,8 +19777,7 @@ function readers.avar(f,fontdata,specification) end return false end - local majorversion=readushort(f) - local minorversion=readushort(f) + local version=readulong(f) local reserved=readushort(f) local nofaxis=readushort(f) local segments={} @@ -20877,7 +20667,7 @@ local function unifymissing(fontdata) fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups) resources.unicodes=nil end -local firstprivate=fonts.privateoffsets.textbase or 0xF0000 +local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000 local puafirst=0xE000 local pualast=0xF8FF local function unifyglyphs(fontdata,usenames) @@ -22832,13 +22622,13 @@ 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.106 +otf.version=3.107 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) -otf.sbixcache=containers.define("fonts","sbix",otf.version,true) +otf.pngcache=containers.define("fonts","png",otf.version,true) otf.pdfcache=containers.define("fonts","pdf",otf.version,true) otf.svgenabled=false -otf.sbixenabled=false +otf.pngenabled=false local otfreaders=otf.readers local hashes=fonts.hashes local definers=fonts.definers @@ -22906,7 +22696,7 @@ function otf.load(filename,sub,instance) report_otf("forced reload of %a due to hard coded flag",filename) reload=true end - if reload then + if reload then report_otf("loading %a, hash %a",filename,hash) starttiming(otfreaders,true) data=otfreaders.loadfont(filename,sub or 1,instance) @@ -22914,7 +22704,7 @@ function otf.load(filename,sub,instance) local used=checkmemory() local resources=data.resources local svgshapes=resources.svgshapes - local sbixshapes=resources.sbixshapes + local pngshapes=resources.pngshapes if cleanup==0 then checkmemory(used,threshold,tracememory) end @@ -22937,15 +22727,15 @@ function otf.load(filename,sub,instance) checkmemory(used,threshold,tracememory) end end - if sbixshapes then - resources.sbixshapes=nil - if otf.sbixenabled then + if pngshapes then + resources.pngshapes=nil + if otf.pngenabled then local timestamp=os.date() - containers.write(otf.sbixcache,hash,{ - sbixshapes=sbixshapes, + containers.write(otf.pngcache,hash,{ + pngshapes=pngshapes, timestamp=timestamp, }) - data.properties.sbix={ + data.properties.png={ hash=hash, timestamp=timestamp, } @@ -26345,22 +26135,17 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip else end end - else + else local discfound=false - local lastdisc=nil local hasmarks=marks[startchar] while current do local char,id=ischar(current,currentfont) if char then if skiphash and skiphash[char] then current=getnext(current) - else - local lg=ligature[char] + else + local lg=ligature[char] if lg then - if not discfound and lastdisc then - discfound=lastdisc - lastdisc=nil - end if marks[char] then hasmarks=true end @@ -26374,42 +26159,82 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip elseif char==false then break elseif id==disc_code then - local replace=getfield(current,"replace") - if replace then - while replace do - local char,id=ischar(replace,currentfont) - if char then - local lg=ligature[char] - if lg then - if marks[char] then - hasmarks=true - end - ligature=lg - replace=getnext(replace) - else - return head,start,false,false - end - else - return head,start,false,false - end - end - stop=current - end - lastdisc=current - current=getnext(current) + discfound=current + break else break end end + if discfound then + local pre,post,replace=getdisc(discfound) + local match + if replace then + local char=ischar(replace,currentfont) + if char and ligature[char] then + match=true + end + end + if not match and pre then + local char=ischar(pre,currentfont) + if char and ligature[char] then + match=true + end + end + if not match and not pre or not replace then + local n=getnext(discfound) + local char=ischar(n,currentfont) + if char and ligature[char] then + match=true + end + end + if match then + local ishead=head==start + local prev=getprev(start) + if stop then + setnext(stop) + local tail=getprev(stop) + local copy=copy_node_list(start) + local liat=find_node_tail(copy) + if pre and replace then + setlink(liat,pre) + end + if replace then + setlink(tail,replace) + end + pre=copy + replace=start + else + setnext(start) + local copy=copy_node(start) + if pre then + setlink(copy,pre) + end + if replace then + setlink(start,replace) + end + pre=copy + replace=start + end + setdisc(discfound,pre,post,replace) + if prev then + setlink(prev,discfound) + else + setprev(discfound) + head=discfound + end + start=discfound + return head,start,true,true + end + end local lig=ligature.ligature if lig then if stop then if trace_ligatures then local stopchar=getchar(stop) - head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) + head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks) logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig)) else - head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) + head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks) end else resetinjection(start) @@ -26418,11 +26243,11 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig)) end end - return head,start,true,discfound + return head,start,true,false else end end - return head,start,false,discfound + return head,start,false,false end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) local startchar=getchar(start) @@ -28901,9 +28726,10 @@ do a=true end if a then - local ok - head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - if start then + local ok,df + head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if df then + elseif start then start=getnext(start) end else @@ -28957,21 +28783,24 @@ do a=true end if a then + local ok,df for i=m[1],m[2] do local step=steps[i] local lookupcache=step.coverage local lookupmatch=lookupcache[char] if lookupmatch then - local ok - head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - if ok then + head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if df then + break + elseif ok then break elseif not start then break end end end - if start then + if df then + elseif start then start=getnext(start) end else @@ -31348,11 +31177,13 @@ else sharedpalettes[name]=values for i=1,#values do local v=values[i] - values[i]=hash[f_color( - max(round((v.r or 0)*255),255)/255, - max(round((v.g or 0)*255),255)/255, - max(round((v.b or 0)*255),255)/255 - )] + if v then + values[i]=hash[f_color( + max(round((v.r or 0)*255),255)/255, + max(round((v.g or 0)*255),255)/255, + max(round((v.b or 0)*255),255)/255 + )] + end end end end @@ -31376,7 +31207,7 @@ local pop={ "pdf","page","Q" } if not LUATEXFUNCTIONALITY or LUATEXFUNCTIONALITY<6472 then start={ "nop" } end -local function initialize(tfmdata,kind,value) +local function initialize(tfmdata,kind,value) if value then local resources=tfmdata.resources local palettes=resources.colorpalettes @@ -31386,7 +31217,13 @@ local function initialize(tfmdata,kind,value) converted=setmetatableindex(convert) resources.converted=converted end - local colorvalues=sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or {} + local colorvalues=sharedpalettes[value] + local default=false + if colorvalues then + default=colorvalues[#colorvalues] + else + colorvalues=converted[palettes[tonumber(value) or 1] or palettes[1]] or {} + end local classes=#colorvalues if classes==0 then return @@ -31399,7 +31236,6 @@ local function initialize(tfmdata,kind,value) { id=0 } } local getactualtext=otf.getactualtext - local default=colorvalues[#colorvalues] local b,e=getactualtext(tounicode(0xFFFD)) local actualb={ "pdf","page",b } local actuale={ "pdf","page",e } @@ -31430,6 +31266,12 @@ local function initialize(tfmdata,kind,value) f=true n=n+1 t[n]=v l=v + else + if f then + n=n+1 t[n]=pop + end + f=false + l=nil end n=n+1 t[n]=charcommand[entry.slot] if s>1 and i<s and goback then @@ -31472,7 +31314,7 @@ do done=f_used(n) hashed[pdf]=done end - return nil,done,nil + return done end else local openpdf=pdfe.new @@ -31485,7 +31327,7 @@ do done=f_used(n) hashed[pdf]=done end - return nil,done,nil + return done end end end @@ -31506,6 +31348,10 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) local b,e=getactualtext(tounicode(0xFFFD)) local actualb={ "pdf","page",b } local actuale={ "pdf","page",e } + local vfimage=lpdf and lpdf.vfimage or function(wd,ht,dp,data,name) + local name=storepdfdata(data) + return { "image",{ filename=name,width=wd,height=ht,depth=dp } } + end for unicode,character in sortedhash(characters) do local index=character.index if index then @@ -31524,21 +31370,18 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) dy=0 end if data then - local setcode,name,nilcode=storepdfdata(data) - if name then - local bt=unicode and getactualtext(unicode) - local wd=character.width or 0 - local ht=character.height or 0 - local dp=character.depth or 0 - character.commands={ - not unicode and actualb or { "pdf","page",(getactualtext(unicode)) }, - downcommand[dp+dy*hfactor], - rightcommand[dx*hfactor], - { "image",{ filename=name,width=wd,height=ht,depth=dp } }, - actuale, - } - character[kind]=true - end + local bt=unicode and getactualtext(unicode) + local wd=character.width or 0 + local ht=character.height or 0 + local dp=character.depth or 0 + character.commands={ + not unicode and actualb or { "pdf","page",(getactualtext(unicode)) }, + downcommand[dp+dy*hfactor], + rightcommand[dx*hfactor], + vfimage(wd,ht,dp,data,name), + actuale, + } + character[kind]=true end end end @@ -31654,40 +31497,40 @@ fonts.handlers.otf.features.register { node=initializesvg, } } -local otfsbix=otf.sbix or {} -otf.sbix=otfsbix -otf.sbixenabled=true +local otfpng=otf.png or {} +otf.png=otfpng +otf.pngenabled=true do - local report_sbix=logs.reporter("fonts","sbix conversion") + local report_png=logs.reporter("fonts","png conversion") local loaddata=io.loaddata local savedata=io.savedata local remove=os.remove local runner=sandbox and sandbox.registerrunner { - name="otfsbix", + name="otfpng", program="gm", - template="convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log", + template="convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log", } if not runner then runner=function() - return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log") + return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log") end end - function otfsbix.topdf(sbixshapes) + function otfpng.topdf(pngshapes) local pdfshapes={} - local sbixfile="temp-otf-sbix-shape.sbix" - local pdffile="temp-otf-sbix-shape.pdf" + local pngfile="temp-otf-png-shape.png" + local pdffile="temp-otf-png-shape.pdf" local nofdone=0 - local indices=sortedkeys(sbixshapes) + local indices=sortedkeys(pngshapes) local nofindices=#indices - report_sbix("processing %i sbix containers",nofindices) + report_png("processing %i png containers",nofindices) statistics.starttiming() for i=1,nofindices do local index=indices[i] - local entry=sbixshapes[index] - local data=entry.data + local entry=pngshapes[index] + local data=entry.data local x=entry.x local y=entry.y - savedata(sbixfile,data) + savedata(pngfile,data) runner() pdfshapes[index]={ x=x~=0 and x or nil, @@ -31696,47 +31539,55 @@ do } nofdone=nofdone+1 if nofdone%100==0 then - report_sbix("%i shapes processed",nofdone) + report_png("%i shapes processed",nofdone) end end - report_sbix("processing %i pdf results",nofindices) - remove(sbixfile) + report_png("processing %i pdf results",nofindices) + remove(pngfile) remove(pdffile) statistics.stoptiming() if statistics.elapsedseconds then - report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-") + report_png("png conversion time %s",statistics.elapsedseconds() or "-") end return pdfshapes end end -local function initializesbix(tfmdata,kind,value) - if value and otf.sbixenabled then - local sbix=tfmdata.properties.sbix - local hash=sbix and sbix.hash - local timestamp=sbix and sbix.timestamp +local function initializepng(tfmdata,kind,value) + if value and otf.pngenabled then + local png=tfmdata.properties.png + local hash=png and png.hash + local timestamp=png and png.timestamp if not hash then return end local pdffile=containers.read(otf.pdfcache,hash) local pdfshapes=pdffile and pdffile.pdfshapes if not pdfshapes or pdffile.timestamp~=timestamp then - local sbixfile=containers.read(otf.sbixcache,hash) - local sbixshapes=sbixfile and sbixfile.sbixshapes - pdfshapes=sbixshapes and otfsbix.topdf(sbixshapes) or {} + local pngfile=containers.read(otf.pngcache,hash) + local pngshapes=pngfile and pngfile.pngshapes + pdfshapes=pngshapes and otfpng.topdf(pngshapes) or {} containers.write(otf.pdfcache,hash,{ pdfshapes=pdfshapes, timestamp=timestamp, }) end - pdftovirtual(tfmdata,pdfshapes,"sbix") + pdftovirtual(tfmdata,pdfshapes,"png") end end fonts.handlers.otf.features.register { name="sbix", description="sbix glyphs", manipulators={ - base=initializesbix, - node=initializesbix, + base=initializepng, + node=initializepng, + } +} +fonts.handlers.otf.features.register { + name="cblc", + description="cblc glyphs", + manipulators={ + base=initializepng, + node=initializepng, } } @@ -32508,7 +32359,7 @@ local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.s 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,Cf,Cg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg +local P,S,R,V,Cmt,C,Ct,Cs,Carg,Cf,Cg,Cc=lpeg.P,lpeg.S,lpeg.R,lpeg.V,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg,lpeg.Cc 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) @@ -32551,14 +32402,21 @@ do local routines,vector,chars,n,m local initialize=function(str,position,size) n=0 - m=size + m=size return position+1 end local setroutine=function(str,position,index,size,filename) - local forward=position+tonumber(size) + if routines[index] then + return false + end + local forward=position+size local stream=decrypt(sub(str,position+1,forward),4330,4) routines[index]={ byte(stream,1,#stream) } - return forward + n=n+1 + if n>=m then + return #str + end + return forward+1 end local setvector=function(str,position,name,size,filename) local forward=position+tonumber(size) @@ -32598,7 +32456,7 @@ do local p_np=spacing*(P("NP")+P("|")) local p_nd=spacing*(P("ND")+P("|")) local p_filterroutines= - (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd*Carg(1),setroutine)*p_np+P(1))^1 + (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd*Carg(1),setroutine)*p_np+(1-p_nd))^1 local p_filtershapes= (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd*Carg(1),setshapes)*p_nd+P(1))^1 local p_filternames=Ct ( @@ -32607,7 +32465,18 @@ do 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 function loadpfbvector(filename,shapestoo) + local key=spacing*P("/")*R("az","AZ") + local str=spacing*Cs { (P("(")/"")*((1-P("\\(")-P("\\)")-S("()"))+V(1))^0*(P(")")/"") } + local num=spacing*(R("09")+S("+-."))^1/tonumber + local arr=spacing*Ct (S("[{")*(num)^0*spacing*S("]}")) + local boo=spacing*(P("true")*Cc(true)+P("false")*Cc(false)) + local nam=spacing*P("/")*Cs(R("az","AZ")^1) + local p_filtermetadata=( + P("/")*Carg(1)*(( + C("version")*str+C("Copyright")*str+C("Notice")*str+C("FullName")*str+C("FamilyName")*str+C("Weight")*str+C("ItalicAngle")*num+C("isFixedPitch")*boo+C("UnderlinePosition")*num+C("UnderlineThickness")*num+C("FontName")*nam+C("FontMatrix")*arr+C("FontBBox")*arr + ) )/function(t,k,v) t[lower(k)]=v end+P(1) + )^0*Carg(1) + local function loadpfbvector(filename,shapestoo,streams) local data=io.loaddata(resolvers.findfile(filename)) if not data then report_pfb("no data in %a",filename) @@ -32625,9 +32494,10 @@ do binary=decrypt(binary,55665,4) local names={} local encoding=lpegmatch(p_filterencoding,ascii) + local metadata=lpegmatch(p_filtermetadata,ascii,1,{}) local glyphs={} routines,vector,chars={},{},{} - if shapestoo then + if shapestoo or streams then lpegmatch(p_filterroutines,binary,1,filename) lpegmatch(p_filtershapes,binary,1,filename) local data={ @@ -32639,13 +32509,13 @@ do } }, } - fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,true) + fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams) else lpegmatch(p_filternames,binary,1,filename) end names=vector routines,vector,chars=nil,nil,nil - return names,encoding,glyphs + return names,encoding,glyphs,metadata end local pfb=handlers.pfb or {} handlers.pfb=pfb @@ -33731,6 +33601,7 @@ if not modules then modules={} end modules ['font-tfm']={ local next,type=next,type local match,format=string.match,string.format local concat,sortedhash=table.concat,table.sortedhash +local idiv=number.idiv 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") @@ -33766,147 +33637,190 @@ function tfm.setfeatures(tfmdata,features) 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 features=constructors.checkedfeatures("tfm",features) - specification.features.normal=features - local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata=newtfmdata +local read_from_tfm,check_tfm do + local tfmreaders=context and tfm.readers + local loadtfmvf=tfmreaders and tfmreaders.loadtfmvf + local loadtfm=font.read_tfm + local loadvf=font.read_vf + directives.register("fonts.tfm.builtin",function(v) + loadtfmvf=tfmreaders and tfmreaders.loadtfmvf + if v and loadtfm then + loadtfmvf=false 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) - tfmenhancers.apply(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) - properties.private=properties.private or tfmdata.private or privateoffset - 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) + read_from_tfm=function(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 + if loadtfmvf then + tfmdata=loadtfmvf(filename,size) + else + tfmdata=loadtfm(filename,size) + end + 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=tfmdata.format or fonts.formats.tfm + properties.usedbitmap=tfmdata.usedbitmap + 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) + tfmenhancers.apply(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 + if size<0 then + size=idiv(65536*-size,100) + end + parameters.factor=1 + parameters.units=1000 + 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) + properties.private=properties.private or tfmdata.private or privateoffset + if newtfmdata then + elseif loadtfmvf then + local fonts=tfmdata.fonts + if fonts then + for i=1,#fonts do + local font=fonts[i] + local id=font.id + if not id then + local name=font.name + local size=font.size + if name and size then + local data,id=constructors.readanddefine(name,size) + if id then + font.id=id + font.name=nil + font.size=nil + end + end + end + end + end + 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=loadvf(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=constructors.readanddefine(n,s) + fontlist[i]={ id=id } + end end end end end + properties.haskerns=true + properties.hasligatures=true + properties.hasitalics=true + resources.unicodes={} + resources.lookuptags={} + depth[filename]=depth[filename]-1 + return tfmdata + else + depth[filename]=depth[filename]-1 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) + check_tfm=function(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 end readers.check_tfm=check_tfm @@ -33966,7 +33880,7 @@ do local encoding=false local vector=false if type(pfbfile)=="string" then - local pfb=fonts.constructors.handlers.pfb + local pfb=constructors.handlers.pfb if pfb and pfb.loadvector then local v,e=pfb.loadvector(pfbfile) if v then @@ -33994,7 +33908,7 @@ do local originals=tfmdata.characters local indices={} local parentfont={ "font",1 } - local private=tfmdata or fonts.constructors.privateoffset + local private=tfmdata.privateoffset or constructors.privateoffset local reported=encdone[tfmfile][encfile] local backmap=vector and table.swapped(vector) local done={} @@ -34084,21 +33998,16 @@ CMapName currentdict /CMap defineresource pop end end end ]] - local flushstreamobject=lpdf and lpdf.flushstreamobject - local setfontattributes=pdf.setfontattributes - if flushstreamobject then - else + local flushstreamobject=lpdf and lpdf.flushstreamobject + local setfontattributes=lpdf and lpdf.setfontattributes + if not flushstreamobject then flushstreamobject=function(data) - return pdf.obj { - immediate=true, - type="stream", - string=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)) + return pdf.setfontattributes(id,data) end end function tfm.addtounicode(tfmdata) @@ -34373,9 +34282,6 @@ function resolvers.name(specification) features.normal=normal end normal.instance=instance - if not callbacks.supported.glyph_stream_provider then - normal.variableshapes=true - end end local suffix=lower(suffixonly(resolved)) if fonts.formats[suffix] then @@ -35233,7 +35139,7 @@ do -- begin closure to overcome local limits and interference if not modules then modules={} end modules ['font-imp-effects']={ version=1.001, - comment="companion to font-ini.mkiv and hand-ini.mkiv", + 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" |