File: kern.rb

package info (click to toggle)
ruby-ttfunk 1.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 916 kB
  • sloc: ruby: 1,719; makefile: 16
file content (79 lines) | stat: -rw-r--r-- 2,693 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
require 'ttfunk/table'

module TTFunk
  class Table
    class Kern < Table
      attr_reader :version
      attr_reader :tables

      def self.encode(kerning, mapping)
        return nil unless kerning.exists? && kerning.tables.any?
        tables = kerning.tables.map { |table| table.recode(mapping) }.compact
        return nil if tables.empty?

        [0, tables.length, tables.join].pack("nnA*")
      end

      private

        def parse!
          @version, num_tables = read(4, "n*")
          @tables = []

          if @version == 1 # Mac OS X fonts
            @version = (@version << 16) + num_tables
            num_tables = read(4, "N").first
            parse_version_1_tables(num_tables)
          else
            parse_version_0_tables(num_tables)
          end
        end

        def parse_version_0_tables(num_tables)
          # It looks like some MS fonts report their kerning subtable lengths
          # wrong. In one case, the length was reported to be some 19366, and yet
          # the table also claimed to hold 14148 pairs (each pair consisting of 6 bytes).
          # You do the math!
          #
          # We're going to assume that the microsoft fonts hold only a single kerning
          # subtable, which occupies the entire length of the kerning table. Worst
          # case, we lose any other subtables that the font contains, but it's better
          # than reading a truncated kerning table.
          #
          # And what's more, it appears to work. So.
          version, length, coverage = read(6, "n*")
          format = coverage >> 8

          add_table format, :version => version, :length => length,
            :coverage => coverage, :data => raw[10..-1],
            :vertical => (coverage & 0x1 == 0),
            :minimum => (coverage & 0x2 != 0),
            :cross => (coverage & 0x4 != 0),
            :override => (coverage & 0x8 != 0)
        end

        def parse_version_1_tables(num_tables)
          num_tables.times do
            length, coverage, tuple_index = read(8, "Nnn")
            format = coverage & 0x0FF

            add_table format, :length => length, :coverage => coverage,
              :tuple_index => tuple_index, :data => io.read(length-8),
              :vertical => (coverage & 0x8000 != 0),
              :cross => (coverage & 0x4000 != 0),
              :variation => (coverage & 0x2000 != 0)
          end
        end

        def add_table(format, attributes={})
          if format == 0
            @tables << Kern::Format0.new(attributes)
          else
            # silently ignore unsupported kerning tables
          end
        end
    end
  end
end

require 'ttfunk/table/kern/format0'