all files / fontkit/src/tables/ aat.coffee

81.03% Statements 47/58
100% Branches 2/2
78.26% Functions 18/23
88.46% Lines 46/52
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     26×     96× 96×     1829× 198× 198× 198× 198×   1829×           96×       11×     1217× 1217×     45× 45×           11×   11×             11×         11×     263×   11×       11×         13×     22×                       96×                                                    
r = require 'restructure'
 
class UnboundedArray extends r.Array
  constructor: (@type) ->
    @length = 0
    
  class UnboundedArrayAccessor
    constructor: (@type, @stream, @parent) ->
      @base = @stream.pos
      @_items = []
      
    getItem: (index) ->
      unless @_items[index]?
        pos = @stream.pos
        @stream.pos = @base + @type.size(null, @parent) * index
        @_items[index] = @type.decode @stream, @parent
        @stream.pos = pos
        
      return @_items[index]
      
    inspect: ->
      return "[UnboundedArray #{@type.constructor.name}]"
      
  decode: (stream, parent) ->
    return new UnboundedArrayAccessor @type, stream, parent
 
exports.UnboundedArray = UnboundedArray
 
exports.LookupTable = LookupTable = (ValueType = r.uint16) ->
  # Helper class that makes internal structures invisible to pointers
  class Shadow
    constructor: (@type) ->
    decode: (stream, ctx) ->
      ctx = ctx.parent.parent
      return @type.decode stream, ctx
    
    size: (val, ctx) ->
      ctx = ctx.parent.parent
      return @type.size val, ctx
    
    encode: (stream, val, ctx) ->
      ctx = ctx.parent.parent
      @type.encode stream, val, ctx
  
  ValueType = new Shadow ValueType
  
  BinarySearchHeader = new r.Struct
    unitSize: r.uint16
    nUnits: r.uint16
    searchRange: r.uint16
    entrySelector: r.uint16
    rangeShift: r.uint16
  
  LookupSegmentSingle = new r.Struct
    lastGlyph: r.uint16
    firstGlyph: r.uint16
    value: ValueType
  
  LookupSegmentArray = new r.Struct
    lastGlyph: r.uint16
    firstGlyph: r.uint16
    values: new r.Pointer(r.uint16, new r.Array(ValueType, -> @lastGlyph - @firstGlyph + 1), type: 'parent')
  
  LookupSingle = new r.Struct
    glyph: r.uint16
    value: ValueType
  
  return new r.VersionedStruct r.uint16,
    0:
      values: new UnboundedArray(ValueType) # length == number of glyphs maybe?
    2:
      binarySearchHeader: BinarySearchHeader
      segments: new r.Array(LookupSegmentSingle, -> @binarySearchHeader.nUnits)
    4:
      binarySearchHeader: BinarySearchHeader
      segments: new r.Array(LookupSegmentArray, -> @binarySearchHeader.nUnits)
    6:
      binarySearchHeader: BinarySearchHeader
      segments: new r.Array(LookupSingle, -> @binarySearchHeader.nUnits)
    8:
      firstGlyph: r.uint16
      count: r.uint16
      values: new r.Array(ValueType, 'count')
 
exports.StateTable = (entryData = {}, lookupType = r.uint16) ->  
  entry = 
    newState: r.uint16
    flags: r.uint16
    
  for key, val of entryData
    entry[key] = val
    
  Entry = new r.Struct entry
  StateArray = new UnboundedArray(new r.Array(r.uint16, -> @nClasses))
 
  StateHeader = new r.Struct
    nClasses: r.uint32
    classTable: new r.Pointer(r.uint32, new LookupTable(lookupType))
    stateArray: new r.Pointer(r.uint32, StateArray)
    entryTable: new r.Pointer(r.uint32, new UnboundedArray(Entry))
    
  return StateHeader
  
# This is the old version of the StateTable structure
exports.StateTable1 = (entryData = {}, lookupType = r.uint16) ->
  ClassLookupTable = new r.Struct
    version: -> 8 # simulate LookupTable
    firstGlyph: r.uint16
    values: new r.Array(r.uint8, r.uint16)
    
  entry = 
    newStateOffset: r.uint16
    # convert offset to stateArray index
    newState: -> (@newStateOffset - (@parent.stateArray.base - @parent._startOffset)) / @parent.nClasses
    flags: r.uint16
    
  for key, val of entryData
    entry[key] = val
    
  Entry = new r.Struct entry
  StateArray = new UnboundedArray(new r.Array(r.uint8, -> @nClasses))
 
  StateHeader1 = new r.Struct
    nClasses: r.uint16
    classTable: new r.Pointer(r.uint16, ClassLookupTable)
    stateArray: new r.Pointer(r.uint16, StateArray)
    entryTable: new r.Pointer(r.uint16, new UnboundedArray(Entry))
    
  return StateHeader1