Code coverage report for fontkit/src/cff/CFFTop.coffee

Statements: 88.89% (48 / 54)      Branches: 50% (2 / 4)      Functions: 77.78% (14 / 18)      Lines: 88.89% (48 / 54)      Ignored: none     

All files » fontkit/src/cff/ » CFFTop.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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 1721 1 1 1 1 1 1 1 1       1     8     8           8 8     8   1   1         1       1       1                     1       1   3 3 3 3 431 431 431 431   3   1         2     1   1   1       1   1             1 1   27 27           21   1           1                                                                                 1           1             1  
r = require 'restructure'
{resolveLength} = require 'restructure/src/utils'
CFFDict = require './CFFDict'
CFFIndex = require './CFFIndex'
CFFPointer = require './CFFPointer'
CFFPrivateDict = require './CFFPrivateDict'
StandardStrings = require './CFFStandardStrings'
{StandardEncoding, ExpertEncoding} = require './CFFEncodings'
{ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset} = require './CFFCharsets';
 
# Checks if an operand is an index of a predefined value,
# otherwise delegates to the provided type.
class PredefinedOp
  constructor: (@predefinedOps, @type) ->
  decode: (stream, parent, operands) ->
    Iif @predefinedOps[operands[0]]
      return @predefinedOps[operands[0]]
      
    return @type.decode(stream, parent, operands)
    
  size: (value, ctx) ->
    return @type.size(value, ctx)
    
  encode: (stream, value, ctx) ->
    index = @predefinedOps.indexOf(value)
    Iif index isnt -1
      return index
      
    return @type.encode(stream, value, ctx)
  
class CFFEncodingVersion extends r.Number
  constructor: ->
    super 'UInt8'
    
  decode: (stream) ->
    return r.uint8.decode(stream) & 0x7f
    
Range1 = new r.Struct
  first: r.uint16
  nLeft: r.uint8
  
Range2 = new r.Struct
  first: r.uint16
  nLeft: r.uint16
 
CFFCustomEncoding = new r.VersionedStruct new CFFEncodingVersion,
  0:
    nCodes: r.uint8
    codes: new r.Array(r.uint8, 'nCodes')
  
  1: 
    nRanges: r.uint8
    ranges: new r.Array(Range1, 'nRanges')
    
  # TODO: supplement?
  
CFFEncoding = new PredefinedOp [ StandardEncoding, ExpertEncoding ], new CFFPointer(CFFCustomEncoding, lazy: true)
 
# Decodes an array of ranges until the total
# length is equal to the provided length.
class RangeArray extends r.Array
  decode: (stream, parent) ->
    length = resolveLength @length, stream, parent
    count = 0
    res = []
    while count < length
      range = @type.decode(stream, parent)
      range.offset = count
      count += range.nLeft + 1
      res.push range
      
    return res
 
CFFCustomCharset = new r.VersionedStruct r.uint8,
  0:
    glyphs: new r.Array(r.uint16, -> @parent.CharStrings.length - 1)
    
  1:
    ranges: new RangeArray(Range1, -> @parent.CharStrings.length - 1)
    
  2:
    ranges: new RangeArray(Range2, -> @parent.CharStrings.length - 1)
 
CFFCharset = new PredefinedOp [ ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset ], new CFFPointer(CFFCustomCharset, lazy: true)
 
FDRange = new r.Struct
  first: r.uint16
  fd: r.uint8
 
FDSelect = new r.VersionedStruct r.uint8,
  0:
    fds: new r.Array(r.uint8, -> @parent.CharStrings.length)
    
  3:
    nRanges: r.uint16
    ranges: new r.Array(FDRange, 'nRanges')
    sentinel: r.uint16
    
class CFFPrivateOp
  ptr = new CFFPointer(CFFPrivateDict)
  decode: (stream, parent, operands) ->
    parent.length = operands[0]
    return ptr.decode(stream, parent, [operands[1]])
    
  size: (dict, ctx) ->
    return [CFFPrivateDict.size(dict, ctx, false), ptr.size(dict, ctx)[0]]
    
  encode: (stream, dict, ctx) ->
    return [CFFPrivateDict.size(dict, ctx, false), ptr.encode(stream, dict, ctx)[0]]
    
FontDict = new CFFDict [
  # key       name                    type(s)                                 default
  [18,        'Private',              new CFFPrivateOp,                       null]
  [[12, 38],  'FontName',             'sid',                                  null]
]
    
CFFTopDict = new CFFDict [
  # key       name                    type(s)                                 default
  [[12, 30],  'ROS',                  ['sid', 'sid', 'number'],               null]
  
  [0,         'version',              'sid',                                  null]
  [1,         'Notice',               'sid',                                  null]
  [[12, 0],   'Copyright',            'sid',                                  null]
  [2,         'FullName',             'sid',                                  null]
  [3,         'FamilyName',           'sid',                                  null]
  [4,         'Weight',               'sid',                                  null]
  [[12, 1],   'isFixedPitch',         'boolean',                              false]
  [[12, 2],   'ItalicAngle',          'number',                               0]
  [[12, 3],   'UnderlinePosition',    'number',                               -100]
  [[12, 4],   'UnderlineThickness',   'number',                               50]
  [[12, 5],   'PaintType',            'number',                               0]
  [[12, 6],   'CharstringType',       'number',                               2]
  [[12, 7],   'FontMatrix',           'array',                                [0.001, 0, 0, 0.001, 0, 0]]
  [13,        'UniqueID',             'number',                               null],
  [5,         'FontBBox',             'array',                                [0, 0, 0, 0]]
  [[12, 8],   'StrokeWidth',          'number',                               0]
  [14,        'XUID',                 'array',                                null]
  [15,        'charset',              CFFCharset,                             ISOAdobeCharset]
  [16,        'Encoding',             CFFEncoding,                            StandardEncoding]
  [17,        'CharStrings',          new CFFPointer(new CFFIndex),           null]
  [18,        'Private',              new CFFPrivateOp,                       null]
  [[12, 20],  'SyntheticBase',        'number',                               null]
  [[12, 21],  'PostScript',           'sid',                                  null]
  [[12, 22],  'BaseFontName',         'sid',                                  null]
  [[12, 23],  'BaseFontBlend',        'delta',                                null]
  
  # CID font specific
  [[12, 31],  'CIDFontVersion',       'number',                               0]
  [[12, 32],  'CIDFontRevision',      'number',                               0]
  [[12, 33],  'CIDFontType',          'number',                               0]
  [[12, 34],  'CIDCount',             'number',                               8720]
  [[12, 35],  'UIDBase',              'number',                               null]
  [[12, 37],  'FDSelect',             new CFFPointer(FDSelect),               null]
  [[12, 36],  'FDArray',              new CFFPointer(new CFFIndex(FontDict)), null]
  [[12, 38],  'FontName',             'sid',                                  null]
]
 
CFFHeader = new r.Struct
  majorVersion:   r.uint8
  minorVersion:   r.uint8
  hdrSize:        r.uint8
  offSize:        r.uint8
  
CFFTop = new r.Struct
  header:             CFFHeader
  nameIndex:          new CFFIndex(new r.String('length'))
  topDictIndex:       new CFFIndex(CFFTopDict)
  stringIndex:        new CFFIndex(new r.String('length'))
  globalSubrIndex:    new CFFIndex
  
module.exports = CFFTop