File: post.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 (157 lines) | stat: -rw-r--r-- 4,253 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
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
# frozen_string_literal: true

require_relative '../table'

module TTFunk
  class Table
    # PostScript (`post`) table.
    #
    # This class can be extended with version-specific modules.
    #
    # @see TTFunk::Table::Post::Format10
    # @see TTFunk::Table::Post::Format20
    # @see TTFunk::Table::Post::Format30
    # @see TTFunk::Table::Post::Format40
    class Post < Table
      # Table version.
      # @return [Integer]
      attr_reader :format

      # Italic angle in counter-clockwise degrees from the vertical.
      # @return [Integer]
      attr_reader :italic_angle

      # Suggested distance of the top of the underline from the baseline
      # @return [Integer]
      attr_reader :underline_position

      # Suggested values for the underline thickness.
      # @return [Integer]
      attr_reader :underline_thickness

      # 0 if the font is proportionally spaced, non-zero if the font is not
      # proportionally spaced.
      # @return [Integer]
      attr_reader :fixed_pitch

      # Minimum memory usage when an OpenType font is downloaded.
      # @return [Integer]
      attr_reader :min_mem_type42

      # Maximum memory usage when an OpenType font is downloaded.
      # @return [Integer]
      attr_reader :max_mem_type42

      # Minimum memory usage when an OpenType font is downloaded as
      # a Type 1 font.
      # @return [Integer]
      attr_reader :min_mem_type1

      # Maximum memory usage when an OpenType font is downloaded as
      # a Type 1 font.
      # @return [Integer]
      attr_reader :max_mem_type1

      # Version-specific fields.
      # @return [TTFunk::Table::Post::Format10, TTFunk::Table::Post::Format20,
      #   TTFunk::Table::Post::Format30, TTFunk::Table::Post::Format40]
      attr_reader :subtable

      # Encode table.
      #
      # @param post [TTFunk::Table::Post]
      # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
      #   are old glyph IDs
      # @return [String, nil]
      def self.encode(post, mapping)
        return if post.nil?

        post.recode(mapping)
      end

      # Is this font monospaced?
      #
      # @return [Boolean]
      def fixed_pitch?
        @fixed_pitch != 0
      end

      # Get glyph name for character code.
      #
      # This is a placeholder.
      #
      # @param _code [Integer]
      # @return [String]
      def glyph_for(_code)
        '.notdef'
      end

      # Re-encode this table.
      #
      # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
      #   are old glyph IDs
      # @return [String]
      def recode(mapping)
        return raw if format == 0x00030000

        table = raw[0, 32]
        table[0, 4] = [0x00020000].pack('N')

        index = []
        strings = []

        mapping.keys.sort.each do |new_id|
          post_glyph = glyph_for(mapping[new_id])
          position = Format10::POSTSCRIPT_GLYPHS.index(post_glyph)
          if position
            index << position
          else
            index << (257 + strings.length)
            strings << post_glyph
          end
        end

        table << [mapping.length, *index].pack('n*')
        strings.each do |string|
          table << [string.length, string].pack('CA*')
        end

        table
      end

      private

      def parse!
        @format, @italic_angle, @underline_position, @underline_thickness,
          @fixed_pitch, @min_mem_type42, @max_mem_type42,
          @min_mem_type1, @max_mem_type1 = read(32, 'N2n2N*')

        @subtable =
          case @format
          when 0x00010000
            extend(Post::Format10)
          when 0x00020000
            extend(Post::Format20)
          when 0x00025000
            raise NotImplementedError,
              'Post format 2.5 is not supported by TTFunk'
          when 0x00030000
            extend(Post::Format30)
          when 0x00040000
            extend(Post::Format40)
          end

        parse_format!
      end

      def parse_format!
        warn(Kernel.format('postscript table format 0x%08X is not supported', @format))
      end
    end
  end
end

require_relative 'post/format10'
require_relative 'post/format20'
require_relative 'post/format30'
require_relative 'post/format40'