Hi, I was playing with the variable font support of ConTeXt's font loader and noticed some issues. 1. While parsing the LocalSubRS and GlobalSubRS Indices, ConTeXt tries to use 16bit count fields as in CFF(1) instead of 32bit fields as in CFF2, reducing the number of found subroutines by a factor of 65536. Effectivly this suppressed all subroutines in the fonts I tested. 2. For fonts where the Top DICT does not contain an FDSelect entry, ConTeXt tries to read the Private dictionary offset from the Top dictionary as in name-keyed CFF1 fonts. This is not the expected behavior for CFF2, where the Top dictionary never contains the Privte offset. Instead, a missing FDSelect means that exactly one entry exists in FDArray which should be used for all CIDs. This caused problems when ConTeXt tried to find the Private directory in order to find local subroutines. A test font demonstrating both issues is "SourceCode Variable" https://github.com/adobe-fonts/source-code-pro/releases: The document \definefontfeature [light] [default] [axis={weight=200}] \definefont [sourcelight] [file:SourceCodeVariable-Roman.otf*light] \starttext \sourcelight Hallo \stoptext generates [...] otf reader > cff > unknown local call 14, case 2 : [] n=0 otf reader > cff > unknown local call 11, case 2 : [] n=0 otf reader > cff > unknown local call 138, case 2 : [] n=0 otf reader > cff > unknown local call 314, case 2 : [300 -12] n=2 otf reader > cff > unknown local call 607, case 2 : [-99 -66 99 174] n=4 otf reader > fatal error in file 'SourceCodeVariable-Roman.otf': ...e0dde776fb1556f32e/formats/luametatex/font-cff-macro.lua:1517: attempt to perform arithmetic on a nil value (local 'v') stack traceback: ...e0dde776fb1556f32e/formats/luametatex/font-otr-macro.lua:2339: in metamethod 'add' ...e0dde776fb1556f32e/formats/luametatex/font-cff-macro.lua:1517: in local 'a' ...e0dde776fb1556f32e/formats/luametatex/font-cff-macro.lua:1980: in upvalue 'process' [...] A possible fix for both issues would be diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua index c2cf0e699..d00637b8e 100644 --- a/tex/context/base/mkiv/font-cff.lua +++ b/tex/context/base/mkiv/font-cff.lua @@ -2265,8 +2265,8 @@ do end -local function readglobals(f,data) - local routines = readlengths(f) +local function readglobals(f,data,version) + local routines = readlengths(f,version == "cff2") for i=1,#routines do routines[i] = readbytetable(f,routines[i]) end @@ -2324,14 +2324,14 @@ local function readprivates(f,data) end end -local function readlocals(f,data,dictionary) +local function readlocals(f,data,dictionary,version) local header = data.header local private = dictionary.private if private then local subroutineoffset = private.data.subroutines if subroutineoffset ~= 0 then setposition(f,header.offset+private.offset+subroutineoffset) - local subroutines = readlengths(f) + local subroutines = readlengths(f,version=="cff2") for i=1,#subroutines do subroutines[i] = readbytetable(f,subroutines[i]) end @@ -2394,7 +2394,7 @@ readers.parsecharstrings = parsecharstrings -- used in font-onr.lua (type 1) local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) local dictionaries = data.dictionaries local dictionary = dictionaries[1] - readglobals(f,data) + readglobals(f,data,version) readcharstrings(f,data,version) if version == "cff2" then dictionary.charset = nil @@ -2402,9 +2402,19 @@ local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) readencodings(f,data) readcharsets(f,data,dictionary) end + local cid = dictionary.cid + local fdarray = cid and cid.fdarray + if fdarray and not dictionary.private then + setposition(f,data.header.offset+fdarray) + local dictionaries = readlengths(f,version=="cff2") + assert(#dictionaries == 1) + dictionaries[1] = readstring(f,dictionaries[1]) + parsedictionaries(data,dictionaries) + dictionary.private = dictionaries[1].private + end readprivates(f,data) parseprivates(data,data.dictionaries) - readlocals(f,data,dictionary) + readlocals(f,data,dictionary,version) startparsing(fontdata,data,streams) parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) stopparsing(fontdata,data) @@ -2416,7 +2426,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) local dictionary = dictionaries[1] local cid = dictionary.cid local cidselect = cid and cid.fdselect - readglobals(f,data) + readglobals(f,data,version) readcharstrings(f,data,version) if version ~= "cff2" then readencodings(f,data) @@ -2462,7 +2472,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) local cidarray = cid.fdarray if cidarray then setposition(f,header.offset+cidarray) - local dictionaries = readlengths(f) + local dictionaries = readlengths(f, version == "cff2") for i=1,#dictionaries do dictionaries[i] = readstring(f,dictionaries[i]) end @@ -2470,7 +2480,7 @@ local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) cid.dictionaries = dictionaries readcidprivates(f,data) for i=1,#dictionaries do - readlocals(f,data,dictionaries[i]) + readlocals(f,data,dictionaries[i],version) end startparsing(fontdata,data,streams) for i=1,#charstrings do ---- Best regards, Marcel