* CFF2 based variable fonts with SubRS
@ 2020-08-26 9:01 Marcel Fabian Krüger
2020-08-26 10:40 ` Hans Hagen
0 siblings, 1 reply; 2+ messages in thread
From: Marcel Fabian Krüger @ 2020-08-26 9:01 UTC (permalink / raw)
To: ConTeXt users list
[-- Attachment #1: Type: text/plain, Size: 5941 bytes --]
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
[-- Attachment #2: cff2_patch.diff --]
[-- Type: text/plain, Size: 3781 bytes --]
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
[-- Attachment #3: Type: text/plain, Size: 493 bytes --]
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the Wiki!
maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage : http://www.pragma-ade.nl / http://context.aanhet.net
archive : https://bitbucket.org/phg/context-mirror/commits/
wiki : http://contextgarden.net
___________________________________________________________________________________
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: CFF2 based variable fonts with SubRS
2020-08-26 9:01 CFF2 based variable fonts with SubRS Marcel Fabian Krüger
@ 2020-08-26 10:40 ` Hans Hagen
0 siblings, 0 replies; 2+ messages in thread
From: Hans Hagen @ 2020-08-26 10:40 UTC (permalink / raw)
To: mailing list for ConTeXt users
On 8/26/2020 11:01 AM, Marcel Fabian Krüger wrote:
> 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
Thanks. I'll check it. (Reminds me to check another issue in a variable
font that I observed recently, something with accuracy, but of could
also be a border case in a viewer as acrobat views ok.) I would not be
surprised of there are more issues because at the time I wrote that code
there were hardly any valid variable fonts and the specs were just
showing up. (Most of those variable fonts were showcases.)
Hans
-----------------------------------------------------------------
Hans Hagen | PRAGMA ADE
Ridderstraat 27 | 8061 GH Hasselt | The Netherlands
tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl
-----------------------------------------------------------------
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the Wiki!
maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage : http://www.pragma-ade.nl / http://context.aanhet.net
archive : https://bitbucket.org/phg/context-mirror/commits/
wiki : http://contextgarden.net
___________________________________________________________________________________
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-08-26 10:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-26 9:01 CFF2 based variable fonts with SubRS Marcel Fabian Krüger
2020-08-26 10:40 ` Hans Hagen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).