@@ -390,7 +390,7 @@ const TOP_DICT_META_CFF2 = [
390390 op : 1207 ,
391391 type : [ 'real' , 'real' , 'real' , 'real' , 'real' , 'real' ] ,
392392 // 1/unitsPerEm 0 0 1/unitsPerEm 0 0
393- // value: [0.001, 0, 0, 0.001, 0, 0]
393+ value : [ 0.001 , 0 , 0 , 0.001 , 0 , 0 ]
394394 } ,
395395] ;
396396
@@ -645,6 +645,9 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
645645 let vsindex = 0 ;
646646 let vstore = [ ] ;
647647 let blendVector ;
648+ const usedOps = [ ] ;
649+ const glyphSubrs = [ ] ;
650+ const glyphGSubrs = [ ] ;
648651
649652 const cffTable = font . tables . cff2 || font . tables . cff ;
650653 defaultWidthX = cffTable . topDict . _defaultWidthX ;
@@ -704,7 +707,7 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
704707 haveWidth = true ;
705708 }
706709
707- function parse ( code ) {
710+ function parse ( code , fromSubr = false ) {
708711 let b1 ;
709712 let b2 ;
710713 let b3 ;
@@ -721,6 +724,7 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
721724 let i = 0 ;
722725 while ( i < code . length ) {
723726 let v = code [ i ] ;
727+ ! fromSubr && v < 32 && usedOps . push ( v ) ;
724728 i += 1 ;
725729 switch ( v ) {
726730 case 1 : // hstem
@@ -838,10 +842,12 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
838842 case 10 : // callsubr
839843 console . log ( 'callsubr' ) ;
840844 codeIndex = stack . pop ( ) + subrsBias ;
845+ glyphSubrs . push ( codeIndex ) ;
846+ glyphGSubrs . push ( null ) ;
841847 subrCode = subrs [ codeIndex ] ;
842848 console . log ( { subrsBias, codeIndex, subrCode} ) ;
843849 if ( subrCode ) {
844- parse ( subrCode ) ;
850+ parse ( subrCode , true ) ;
845851 }
846852
847853 break ;
@@ -1317,10 +1323,12 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
13171323 case 29 : // callgsubr
13181324 console . log ( 'callgsubr' ) ;
13191325 codeIndex = stack . pop ( ) + font . gsubrsBias ;
1326+ glyphSubrs . push ( null ) ;
1327+ glyphGSubrs . push ( codeIndex ) ;
13201328 subrCode = font . gsubrs [ codeIndex ] ;
13211329 console . log ( { gsubrBias : font . gsubrsBias , codeIndex, subrCode} ) ;
13221330 if ( subrCode ) {
1323- parse ( subrCode ) ;
1331+ parse ( subrCode , true ) ;
13241332 }
13251333
13261334 break ;
@@ -1464,6 +1472,15 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
14641472 glyph . advanceWidth = width ;
14651473 }
14661474
1475+
1476+ // glyph only consists of (global) subroutines
1477+ if ( usedOps . filter ( o => o === 10 || o === 29 ) . length === glyphSubrs . filter ( s => s !== null ) . length + glyphGSubrs . filter ( s => s !== null ) . length ) {
1478+ glyph . subrs = glyphSubrs ;
1479+ glyph . gsubrs = glyphGSubrs ;
1480+ console . log ( '#########' ) ;
1481+ console . log ( glyph ) ;
1482+ }
1483+
14671484 return p ;
14681485}
14691486
@@ -1778,11 +1795,40 @@ function makeCharsets(glyphNames, strings) {
17781795 return t ;
17791796}
17801797
1781- function glyphToOps ( glyph , version ) {
1798+ function glyphToOps ( glyph , version , font ) {
17821799 // @TODO : write existing blend data if we already have a CFF2 font
17831800 // @TODO : if we have a gvar table, we'll need to convert its data to CFF2 blend data
17841801 const ops = [ ] ;
17851802 const path = glyph . path ;
1803+
1804+ // @TODO : Right now we only make use of (global) sub routines if the whole glyph is made up of them
1805+ // and they are already defined on the glyph. In the future we'll need an algorithm that finds
1806+ // candidates for sub routines and extracts them from the glyphs, replacing the actual commands
1807+ if ( glyph . subrs && glyph . gsubrs && glyph . subrs . length === glyph . gsubrs . length ) {
1808+ const cffTable = font . tables [ version < 2 ? 'cff' : 'cff2' ] ;
1809+ const fdIndex = cffTable . topDict . _fdSelect ? cffTable . topDict . _fdSelect [ glyph . index ] : 0 ;
1810+ const fdDict = cffTable . topDict . _fdArray [ fdIndex ] ;
1811+ for ( let i = 0 ; i < glyph . subrs . length ; i ++ ) {
1812+ let v = glyph . subrs [ i ] ;
1813+ let name = 'subr' ;
1814+ let op = 10 ;
1815+ if ( v === null ) {
1816+ v = glyph . gsubrs [ i ] ;
1817+ name = 'gsubr' ;
1818+ op = 29 ;
1819+ if ( v === null ) {
1820+ throw Error ( `Inconsistend subr/gsubr values on glyph ${ glyph . index } ` ) ;
1821+ }
1822+ v -= font . gsubrsBias ;
1823+ } else {
1824+ v -= fdDict . _subrsBias ;
1825+ }
1826+ ops . push ( { name : `${ name } Index` , type : 'NUMBER' , value : v } ) ;
1827+ ops . push ( { name, type : 'OP' , value : op } ) ;
1828+ }
1829+ return ops ;
1830+ }
1831+
17861832 if ( version < 2 ) {
17871833 ops . push ( { name : 'width' , type : 'NUMBER' , value : glyph . advanceWidth } ) ;
17881834 }
@@ -1882,7 +1928,7 @@ function makeCharStringsIndex(glyphs, version) {
18821928
18831929 for ( let i = 0 ; i < glyphs . length ; i += 1 ) {
18841930 const glyph = glyphs . get ( i ) ;
1885- const ops = glyphToOps ( glyph , version ) ;
1931+ const ops = glyphToOps ( glyph , version , glyphs . font ) ;
18861932 t . charStrings . push ( { name : glyph . name , type : 'CHARSTRING' , value : ops } ) ;
18871933 }
18881934
0 commit comments