@@ -390,7 +390,7 @@ const TOP_DICT_META_CFF2 = [
390
390
op : 1207 ,
391
391
type : [ 'real' , 'real' , 'real' , 'real' , 'real' , 'real' ] ,
392
392
// 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 ]
394
394
} ,
395
395
] ;
396
396
@@ -645,6 +645,9 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
645
645
let vsindex = 0 ;
646
646
let vstore = [ ] ;
647
647
let blendVector ;
648
+ const usedOps = [ ] ;
649
+ const glyphSubrs = [ ] ;
650
+ const glyphGSubrs = [ ] ;
648
651
649
652
const cffTable = font . tables . cff2 || font . tables . cff ;
650
653
defaultWidthX = cffTable . topDict . _defaultWidthX ;
@@ -704,7 +707,7 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
704
707
haveWidth = true ;
705
708
}
706
709
707
- function parse ( code ) {
710
+ function parse ( code , fromSubr = false ) {
708
711
let b1 ;
709
712
let b2 ;
710
713
let b3 ;
@@ -721,6 +724,7 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
721
724
let i = 0 ;
722
725
while ( i < code . length ) {
723
726
let v = code [ i ] ;
727
+ ! fromSubr && v < 32 && usedOps . push ( v ) ;
724
728
i += 1 ;
725
729
switch ( v ) {
726
730
case 1 : // hstem
@@ -838,10 +842,12 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
838
842
case 10 : // callsubr
839
843
console . log ( 'callsubr' ) ;
840
844
codeIndex = stack . pop ( ) + subrsBias ;
845
+ glyphSubrs . push ( codeIndex ) ;
846
+ glyphGSubrs . push ( null ) ;
841
847
subrCode = subrs [ codeIndex ] ;
842
848
console . log ( { subrsBias, codeIndex, subrCode} ) ;
843
849
if ( subrCode ) {
844
- parse ( subrCode ) ;
850
+ parse ( subrCode , true ) ;
845
851
}
846
852
847
853
break ;
@@ -1317,10 +1323,12 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
1317
1323
case 29 : // callgsubr
1318
1324
console . log ( 'callgsubr' ) ;
1319
1325
codeIndex = stack . pop ( ) + font . gsubrsBias ;
1326
+ glyphSubrs . push ( null ) ;
1327
+ glyphGSubrs . push ( codeIndex ) ;
1320
1328
subrCode = font . gsubrs [ codeIndex ] ;
1321
1329
console . log ( { gsubrBias : font . gsubrsBias , codeIndex, subrCode} ) ;
1322
1330
if ( subrCode ) {
1323
- parse ( subrCode ) ;
1331
+ parse ( subrCode , true ) ;
1324
1332
}
1325
1333
1326
1334
break ;
@@ -1464,6 +1472,15 @@ function parseCFFCharstring(font, glyph, code, version, coords) {
1464
1472
glyph . advanceWidth = width ;
1465
1473
}
1466
1474
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
+
1467
1484
return p ;
1468
1485
}
1469
1486
@@ -1778,11 +1795,40 @@ function makeCharsets(glyphNames, strings) {
1778
1795
return t ;
1779
1796
}
1780
1797
1781
- function glyphToOps ( glyph , version ) {
1798
+ function glyphToOps ( glyph , version , font ) {
1782
1799
// @TODO : write existing blend data if we already have a CFF2 font
1783
1800
// @TODO : if we have a gvar table, we'll need to convert its data to CFF2 blend data
1784
1801
const ops = [ ] ;
1785
1802
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
+
1786
1832
if ( version < 2 ) {
1787
1833
ops . push ( { name : 'width' , type : 'NUMBER' , value : glyph . advanceWidth } ) ;
1788
1834
}
@@ -1882,7 +1928,7 @@ function makeCharStringsIndex(glyphs, version) {
1882
1928
1883
1929
for ( let i = 0 ; i < glyphs . length ; i += 1 ) {
1884
1930
const glyph = glyphs . get ( i ) ;
1885
- const ops = glyphToOps ( glyph , version ) ;
1931
+ const ops = glyphToOps ( glyph , version , glyphs . font ) ;
1886
1932
t . charStrings . push ( { name : glyph . name , type : 'CHARSTRING' , value : ops } ) ;
1887
1933
}
1888
1934
0 commit comments