Code coverage report for fontkit/src/subset/CFFSubset.coffee

Statements: 96.55% (84 / 87)      Branches: 75% (12 / 16)      Functions: 100% (9 / 9)      Lines: 98.81% (83 / 84)      Ignored: none     

All files » fontkit/src/subset/ » CFFSubset.coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 1381 1 1 1   1   3 3 3       2 2   2 8   8 8   8 18   2     5 5 16630 34 34   16596   5   1 7 7 130   7     1 1       1 1 1 3 3   3 2 2   3 3   3 3 3 6   1 2 2 2 2   1     1 1 5 5   5 10   1 1   1 1             22   14 14 14     2   2 2     2 2 2 2 2   2 18   2 2   2 1   1   2             2   1  
Subset = require './Subset'
CFFTop = require '../cff/CFFTop'
CFFPrivateDict = require '../cff/CFFPrivateDict'
standardStrings = require '../cff/CFFStandardStrings'
 
class CFFSubset extends Subset
  constructor: ->
    super
    @cff = @font['CFF ']
    Iunless @cff
      throw new Error 'Not a CFF Font'
  
  subsetCharstrings: ->
    @charstrings = []
    gsubrs = {}
 
    for gid in @glyphs
      @charstrings.push @cff.getCharString gid
 
      glyph = @font.getGlyph gid
      path = glyph.path # this causes the glyph to be parsed
 
      for subr of glyph._usedGsubrs
        gsubrs[subr] = true
        
    @gsubrs = @subsetSubrs @cff.globalSubrIndex, gsubrs
    
  subsetSubrs: (subrs, used) ->
    res = []
    for subr, i in subrs
      if used[i]
        @cff.stream.pos = subr.offset
        res.push @cff.stream.readBuffer subr.length
      else
        res.push new Buffer([11]) # return
        
    return res
    
  shallowCopy = (obj) ->
    res = {}
    for key, val of obj
      res[key] = val
      
    return res
    
  subsetFontdict: (topDict) ->
    topDict.FDArray = []
    topDict.FDSelect =
      version: 0
      fds: []
    
    used_fds = {}
    used_subrs = []
    for gid in @glyphs
      fd = @cff.fdForGlyph gid
      Icontinue unless fd?
      
      unless used_fds[fd]
        topDict.FDArray.push shallowCopy @cff.topDict.FDArray[fd]
        used_subrs.push {}
        
      used_fds[fd] = true
      topDict.FDSelect.fds.push topDict.FDArray.length - 1
      
      glyph = @font.getGlyph gid
      path = glyph.path # this causes the glyph to be parsed
      for subr of glyph._usedSubrs
        used_subrs[used_subrs.length - 1][subr] = true
      
    for dict, i in topDict.FDArray
      delete dict.FontName
      Eif dict.Private?.Subrs
        dict.Private = shallowCopy dict.Private
        dict.Private.Subrs = @subsetSubrs dict.Private.Subrs, used_subrs[i]
        
    return
    
  createCIDFontdict: (topDict) ->
    used_subrs = {}
    for gid in @glyphs
      glyph = @font.getGlyph gid
      path = glyph.path # this causes the glyph to be parsed
        
      for subr of glyph._usedSubrs
        used_subrs[subr] = true
    
    privateDict = shallowCopy @cff.topDict.Private
    privateDict.Subrs = @subsetSubrs @cff.topDict.Private.Subrs, used_subrs
    
    topDict.FDArray = [{ Private: privateDict }]
    topDict.FDSelect =
      version: 3
      nRanges: 1
      ranges: [{ first: 0, fd: 0 }]
      sentinel: @charstrings.length
      
  addString: (string) ->
    return null unless string
    
    @strings ?= []
    @strings.push string
    return standardStrings.length + @strings.length - 1
    
  encode: (stream) ->
    @subsetCharstrings()
    
    charset = 
      version: Iif @charstrings.length > 255 then 2 else 1
      ranges: [{ first: 1, nLeft: @charstrings.length - 2 }]
    
    topDict = shallowCopy @cff.topDict
    topDict.Private = null
    topDict.charset = charset
    topDict.Encoding = null
    topDict.CharStrings = @charstrings
    
    for key in ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName']
      topDict[key] = @addString @cff.string topDict[key]
      
    topDict.ROS = [@addString('Adobe'), @addString('Identity'), 0]
    topDict.CIDCount = @charstrings.length
    
    if @cff.isCIDFont
      @subsetFontdict topDict
    else
      @createCIDFontdict topDict
    
    top =
      header: @cff.header
      nameIndex: [@cff.postscriptName]
      topDictIndex: [topDict]
      stringIndex: @strings
      globalSubrIndex: @gsubrs
      
    CFFTop.encode stream, top
    
module.exports = CFFSubset