File: format0.rb

package info (click to toggle)
ruby-ttfunk 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,472 kB
  • sloc: ruby: 7,954; makefile: 7
file content (90 lines) | stat: -rw-r--r-- 2,393 bytes parent folder | download
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
# frozen_string_literal: true

require_relative '../../reader'

module TTFunk
  class Table
    class Kern
      # Format 0 kerning subtable.
      class Format0
        include Reader

        # Subtable attributes.
        # @return [Hash{Symbol => any}]
        attr_reader :attributes

        # Kerning pairs.
        # @return [Hash{Array(Integer, Integer) => Integer}]
        attr_reader :pairs

        # @param attributes [Hash{Symbol => any}]
        def initialize(attributes = {})
          @attributes = attributes

          num_pairs, *pairs = attributes.delete(:data).unpack('nx6n*')

          @pairs = {}
          num_pairs.times do |i|
            # sanity check, in case there's a bad length somewhere
            break if (i * 3) + 2 > pairs.length

            left = pairs[i * 3]
            right = pairs[(i * 3) + 1]
            value = to_signed(pairs[(i * 3) + 2])
            @pairs[[left, right]] = value
          end
        end

        # Is this vertical kerning?
        # @return [Boolean]
        def vertical?
          @attributes[:vertical]
        end

        # Is this horizontal kerning?
        # @return [Boolean]
        def horizontal?
          !vertical?
        end

        # Is this cross-stream kerning?
        # @return [Boolean]
        def cross_stream?
          @attributes[:cross]
        end

        # Recode this subtable using the specified mapping.
        #
        # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs,
        #   values are old glyph IDs
        # @return [String]
        def recode(mapping)
          subset = []
          pairs.each do |(left, right), value|
            if mapping[left] && mapping[right]
              subset << [mapping[left], mapping[right], value]
            end
          end

          return if subset.empty?

          num_pairs = subset.length
          search_range = 2 * (2**Integer(Math.log(num_pairs) / Math.log(2)))
          entry_selector = Integer(Math.log(search_range / 2) / Math.log(2))
          range_shift = (2 * num_pairs) - search_range

          [
            attributes[:version],
            (num_pairs * 6) + 14,
            attributes[:coverage],
            num_pairs,
            search_range,
            entry_selector,
            range_shift,
            subset,
          ].flatten.pack('n*')
        end
      end
    end
  end
end