ttfunk 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +60 -0
  5. data/README.md +2 -1
  6. data/lib/ttfunk.rb +45 -0
  7. data/lib/ttfunk/aggregate.rb +15 -0
  8. data/lib/ttfunk/bin_utils.rb +47 -0
  9. data/lib/ttfunk/bit_field.rb +31 -0
  10. data/lib/ttfunk/collection.rb +3 -1
  11. data/lib/ttfunk/directory.rb +6 -0
  12. data/lib/ttfunk/encoded_string.rb +97 -0
  13. data/lib/ttfunk/max.rb +25 -0
  14. data/lib/ttfunk/min.rb +25 -0
  15. data/lib/ttfunk/one_based_array.rb +36 -0
  16. data/lib/ttfunk/otf_encoder.rb +61 -0
  17. data/lib/ttfunk/placeholder.rb +13 -0
  18. data/lib/ttfunk/reader.rb +34 -32
  19. data/lib/ttfunk/resource_file.rb +7 -5
  20. data/lib/ttfunk/sci_form.rb +29 -0
  21. data/lib/ttfunk/sub_table.rb +38 -0
  22. data/lib/ttfunk/subset.rb +2 -0
  23. data/lib/ttfunk/subset/base.rb +61 -120
  24. data/lib/ttfunk/subset/code_page.rb +89 -0
  25. data/lib/ttfunk/subset/mac_roman.rb +5 -42
  26. data/lib/ttfunk/subset/unicode.rb +12 -6
  27. data/lib/ttfunk/subset/unicode_8bit.rb +14 -12
  28. data/lib/ttfunk/subset/windows_1252.rb +5 -47
  29. data/lib/ttfunk/subset_collection.rb +4 -0
  30. data/lib/ttfunk/sum.rb +20 -0
  31. data/lib/ttfunk/table.rb +4 -0
  32. data/lib/ttfunk/table/cff.rb +69 -0
  33. data/lib/ttfunk/table/cff/charset.rb +212 -0
  34. data/lib/ttfunk/table/cff/charsets.rb +14 -0
  35. data/lib/ttfunk/table/cff/charsets/expert.rb +189 -0
  36. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +119 -0
  37. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +241 -0
  38. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +404 -0
  39. data/lib/ttfunk/table/cff/charstring.rb +487 -0
  40. data/lib/ttfunk/table/cff/charstrings_index.rb +39 -0
  41. data/lib/ttfunk/table/cff/dict.rb +266 -0
  42. data/lib/ttfunk/table/cff/encoding.rb +220 -0
  43. data/lib/ttfunk/table/cff/encodings.rb +12 -0
  44. data/lib/ttfunk/table/cff/encodings/expert.rb +206 -0
  45. data/lib/ttfunk/table/cff/encodings/standard.rb +181 -0
  46. data/lib/ttfunk/table/cff/fd_selector.rb +150 -0
  47. data/lib/ttfunk/table/cff/font_dict.rb +79 -0
  48. data/lib/ttfunk/table/cff/font_index.rb +29 -0
  49. data/lib/ttfunk/table/cff/header.rb +33 -0
  50. data/lib/ttfunk/table/cff/index.rb +125 -0
  51. data/lib/ttfunk/table/cff/one_based_index.rb +31 -0
  52. data/lib/ttfunk/table/cff/path.rb +66 -0
  53. data/lib/ttfunk/table/cff/private_dict.rb +84 -0
  54. data/lib/ttfunk/table/cff/subr_index.rb +19 -0
  55. data/lib/ttfunk/table/cff/top_dict.rb +230 -0
  56. data/lib/ttfunk/table/cff/top_index.rb +16 -0
  57. data/lib/ttfunk/table/cmap.rb +4 -4
  58. data/lib/ttfunk/table/cmap/format00.rb +1 -2
  59. data/lib/ttfunk/table/cmap/format04.rb +11 -3
  60. data/lib/ttfunk/table/cmap/format06.rb +2 -0
  61. data/lib/ttfunk/table/cmap/format10.rb +2 -0
  62. data/lib/ttfunk/table/cmap/format12.rb +2 -0
  63. data/lib/ttfunk/table/cmap/subtable.rb +12 -8
  64. data/lib/ttfunk/table/dsig.rb +50 -0
  65. data/lib/ttfunk/table/glyf.rb +11 -9
  66. data/lib/ttfunk/table/glyf/compound.rb +14 -7
  67. data/lib/ttfunk/table/glyf/path_based.rb +47 -0
  68. data/lib/ttfunk/table/glyf/simple.rb +21 -15
  69. data/lib/ttfunk/table/head.rb +43 -5
  70. data/lib/ttfunk/table/hhea.rb +47 -4
  71. data/lib/ttfunk/table/hmtx.rb +11 -4
  72. data/lib/ttfunk/table/kern.rb +3 -0
  73. data/lib/ttfunk/table/kern/format0.rb +3 -0
  74. data/lib/ttfunk/table/loca.rb +2 -0
  75. data/lib/ttfunk/table/maxp.rb +144 -10
  76. data/lib/ttfunk/table/name.rb +75 -37
  77. data/lib/ttfunk/table/os2.rb +327 -4
  78. data/lib/ttfunk/table/post.rb +8 -1
  79. data/lib/ttfunk/table/post/format10.rb +2 -0
  80. data/lib/ttfunk/table/post/format20.rb +5 -1
  81. data/lib/ttfunk/table/post/format30.rb +2 -0
  82. data/lib/ttfunk/table/post/format40.rb +2 -0
  83. data/lib/ttfunk/table/sbix.rb +2 -0
  84. data/lib/ttfunk/table/simple.rb +2 -0
  85. data/lib/ttfunk/table/vorg.rb +54 -0
  86. data/lib/ttfunk/ttf_encoder.rb +220 -0
  87. metadata +88 -20
  88. metadata.gz.sig +0 -0
  89. data/lib/ttfunk/encoding/mac_roman.rb +0 -100
  90. data/lib/ttfunk/encoding/windows_1252.rb +0 -76
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ module Encodings
7
+ autoload :EXPERT, 'ttfunk/table/cff/encodings/expert'
8
+ autoload :STANDARD, 'ttfunk/table/cff/encodings/standard'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ module Encodings
7
+ EXPERT = OneBasedArray.new(
8
+ [
9
+ *[0] * 31,
10
+ 1,
11
+ 229,
12
+ 230,
13
+ 0,
14
+ 231,
15
+ 232,
16
+ 233,
17
+ 234,
18
+ 235,
19
+ 236,
20
+ 237,
21
+ 238,
22
+ 13,
23
+ 14,
24
+ 15,
25
+ 99,
26
+ 239,
27
+ 240,
28
+ 241,
29
+ 242,
30
+ 243,
31
+ 244,
32
+ 245,
33
+ 246,
34
+ 247,
35
+ 248,
36
+ 27,
37
+ 28,
38
+ 249,
39
+ 250,
40
+ 251,
41
+ 252,
42
+ 0,
43
+ 253,
44
+ 254,
45
+ 255,
46
+ 256,
47
+ 257,
48
+ 0,
49
+ 0,
50
+ 0,
51
+ 258,
52
+ 0,
53
+ 0,
54
+ 259,
55
+ 260,
56
+ 261,
57
+ 262,
58
+ 0,
59
+ 0,
60
+ 263,
61
+ 264,
62
+ 265,
63
+ 0,
64
+ 266,
65
+ 109,
66
+ 110,
67
+ 267,
68
+ 268,
69
+ 269,
70
+ 0,
71
+ 270,
72
+ 271,
73
+ 272,
74
+ 273,
75
+ 274,
76
+ 275,
77
+ 276,
78
+ 277,
79
+ 278,
80
+ 279,
81
+ 280,
82
+ 281,
83
+ 282,
84
+ 283,
85
+ 284,
86
+ 285,
87
+ 286,
88
+ 287,
89
+ 288,
90
+ 289,
91
+ 290,
92
+ 291,
93
+ 292,
94
+ 293,
95
+ 294,
96
+ 295,
97
+ 296,
98
+ 297,
99
+ 298,
100
+ 299,
101
+ 300,
102
+ 301,
103
+ 302,
104
+ 303,
105
+ *[0] * 34,
106
+ 304,
107
+ 305,
108
+ 306,
109
+ 0,
110
+ 0,
111
+ 307,
112
+ 308,
113
+ 309,
114
+ 310,
115
+ 311,
116
+ 0,
117
+ 312,
118
+ 0,
119
+ 0,
120
+ 313,
121
+ 0,
122
+ 0,
123
+ 314,
124
+ 315,
125
+ 0,
126
+ 0,
127
+ 316,
128
+ 317,
129
+ 318,
130
+ 0,
131
+ 0,
132
+ 0,
133
+ 158,
134
+ 155,
135
+ 163,
136
+ 319,
137
+ 320,
138
+ 321,
139
+ 322,
140
+ 323,
141
+ 324,
142
+ 325,
143
+ 0,
144
+ 0,
145
+ 326,
146
+ 150,
147
+ 164,
148
+ 169,
149
+ 327,
150
+ 328,
151
+ 329,
152
+ 330,
153
+ 331,
154
+ 332,
155
+ 333,
156
+ 334,
157
+ 335,
158
+ 336,
159
+ 337,
160
+ 338,
161
+ 339,
162
+ 340,
163
+ 341,
164
+ 342,
165
+ 343,
166
+ 344,
167
+ 345,
168
+ 346,
169
+ 347,
170
+ 348,
171
+ 349,
172
+ 350,
173
+ 351,
174
+ 352,
175
+ 353,
176
+ 354,
177
+ 355,
178
+ 356,
179
+ 357,
180
+ 358,
181
+ 359,
182
+ 360,
183
+ 361,
184
+ 362,
185
+ 363,
186
+ 364,
187
+ 365,
188
+ 366,
189
+ 367,
190
+ 368,
191
+ 369,
192
+ 370,
193
+ 371,
194
+ 372,
195
+ 373,
196
+ 374,
197
+ 375,
198
+ 376,
199
+ 377,
200
+ 378
201
+ ]
202
+ ).freeze
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ module Encodings
7
+ STANDARD = OneBasedArray.new(
8
+ [
9
+ *[0] * 31,
10
+ 1,
11
+ 2,
12
+ 3,
13
+ 4,
14
+ 5,
15
+ 6,
16
+ 7,
17
+ 8,
18
+ 9,
19
+ 10,
20
+ 11,
21
+ 12,
22
+ 13,
23
+ 14,
24
+ 15,
25
+ 16,
26
+ 17,
27
+ 18,
28
+ 19,
29
+ 20,
30
+ 21,
31
+ 22,
32
+ 23,
33
+ 24,
34
+ 25,
35
+ 26,
36
+ 27,
37
+ 28,
38
+ 29,
39
+ 30,
40
+ 31,
41
+ 32,
42
+ 33,
43
+ 34,
44
+ 35,
45
+ 36,
46
+ 37,
47
+ 38,
48
+ 39,
49
+ 40,
50
+ 41,
51
+ 42,
52
+ 43,
53
+ 44,
54
+ 45,
55
+ 46,
56
+ 47,
57
+ 48,
58
+ 49,
59
+ 50,
60
+ 51,
61
+ 52,
62
+ 53,
63
+ 54,
64
+ 55,
65
+ 56,
66
+ 57,
67
+ 58,
68
+ 59,
69
+ 60,
70
+ 61,
71
+ 62,
72
+ 63,
73
+ 64,
74
+ 65,
75
+ 66,
76
+ 67,
77
+ 68,
78
+ 69,
79
+ 70,
80
+ 71,
81
+ 72,
82
+ 73,
83
+ 74,
84
+ 75,
85
+ 76,
86
+ 77,
87
+ 78,
88
+ 79,
89
+ 80,
90
+ 81,
91
+ 82,
92
+ 83,
93
+ 84,
94
+ 85,
95
+ 86,
96
+ 87,
97
+ 88,
98
+ 89,
99
+ 90,
100
+ 91,
101
+ 92,
102
+ 93,
103
+ 94,
104
+ 95,
105
+ *[0] * 34,
106
+ 96,
107
+ 97,
108
+ 98,
109
+ 99,
110
+ 100,
111
+ 101,
112
+ 102,
113
+ 103,
114
+ 104,
115
+ 105,
116
+ 106,
117
+ 107,
118
+ 108,
119
+ 109,
120
+ 110,
121
+ 0,
122
+ 111,
123
+ 112,
124
+ 113,
125
+ 114,
126
+ 0,
127
+ 115,
128
+ 116,
129
+ 117,
130
+ 118,
131
+ 119,
132
+ 120,
133
+ 121,
134
+ 122,
135
+ 0,
136
+ 123,
137
+ 0,
138
+ 124,
139
+ 125,
140
+ 126,
141
+ 127,
142
+ 128,
143
+ 129,
144
+ 130,
145
+ 131,
146
+ 0,
147
+ 132,
148
+ 133,
149
+ 0,
150
+ 134,
151
+ 135,
152
+ 136,
153
+ 137,
154
+ *[0] * 16,
155
+ 138,
156
+ 0,
157
+ 139,
158
+ *[0] * 4,
159
+ 140,
160
+ 141,
161
+ 142,
162
+ 143,
163
+ *[0] * 5,
164
+ 144,
165
+ 0,
166
+ 0,
167
+ 0,
168
+ 145,
169
+ 0,
170
+ 0,
171
+ 146,
172
+ 147,
173
+ 148,
174
+ 149,
175
+ *[0] * 4
176
+ ]
177
+ ).freeze
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ class FdSelector < TTFunk::SubTable
7
+ include Enumerable
8
+
9
+ ARRAY_FORMAT = 0
10
+ RANGE_FORMAT = 3
11
+
12
+ RANGE_ENTRY_SIZE = 3
13
+ ARRAY_ENTRY_SIZE = 1
14
+
15
+ attr_reader :top_dict, :count, :entries, :n_glyphs
16
+
17
+ def initialize(top_dict, file, offset, length = nil)
18
+ @top_dict = top_dict
19
+ super(file, offset, length)
20
+ end
21
+
22
+ def [](glyph_id)
23
+ case format_sym
24
+ when :array_format
25
+ entries[glyph_id]
26
+
27
+ when :range_format
28
+ if (entry = range_cache[glyph_id])
29
+ return entry
30
+ end
31
+
32
+ range, entry = entries.bsearch do |rng, _|
33
+ if rng.cover?(glyph_id)
34
+ 0
35
+ elsif glyph_id < rng.first
36
+ -1
37
+ else
38
+ 1
39
+ end
40
+ end
41
+
42
+ range.each { |i| range_cache[i] = entry }
43
+ entry
44
+ end
45
+ end
46
+
47
+ def each
48
+ return to_enum(__method__) unless block_given?
49
+
50
+ count.times { |i| yield self[i] }
51
+ end
52
+
53
+ # mapping is new -> old glyph ids
54
+ def encode(mapping)
55
+ # get list of [new_gid, fd_index] pairs
56
+ new_indices = mapping.keys.sort.map do |new_gid|
57
+ [new_gid, self[mapping[new_gid]]]
58
+ end
59
+
60
+ ranges = rangify_gids(new_indices)
61
+ total_range_size = ranges.size * RANGE_ENTRY_SIZE
62
+ total_array_size = new_indices.size * ARRAY_ENTRY_SIZE
63
+
64
+ ''.b.tap do |result|
65
+ if total_array_size <= total_range_size
66
+ result << [ARRAY_FORMAT].pack('C')
67
+ result << new_indices.map(&:last).pack('C*')
68
+ else
69
+ result << [RANGE_FORMAT, ranges.size].pack('Cn')
70
+ ranges.each { |range| result << range.pack('nC') }
71
+
72
+ # "A sentinel GID follows the last range element and serves to
73
+ # delimit the last range in the array. (The sentinel GID is set
74
+ # equal to the number of glyphs in the font. That is, its value
75
+ # is 1 greater than the last GID in the font)."
76
+ result << [new_indices.size].pack('n')
77
+ end
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def range_cache
84
+ @range_cache ||= {}
85
+ end
86
+
87
+ # values is an array of [new_gid, fd_index] pairs
88
+ def rangify_gids(values)
89
+ start_gid = 0
90
+
91
+ [].tap do |ranges|
92
+ values.each_cons(2) do |(_, first_idx), (sec_gid, sec_idx)|
93
+ if first_idx != sec_idx
94
+ ranges << [start_gid, first_idx]
95
+ start_gid = sec_gid
96
+ end
97
+ end
98
+
99
+ ranges << [start_gid, values.last[1]]
100
+ end
101
+ end
102
+
103
+ def parse!
104
+ @format = read(1, 'C').first
105
+ @length = 1
106
+
107
+ case format_sym
108
+ when :array_format
109
+ @n_glyphs = top_dict.charstrings_index.count
110
+ data = io.read(n_glyphs)
111
+ @length += data.bytesize
112
+ @count = data.bytesize
113
+ @entries = data.bytes
114
+
115
+ when :range_format
116
+ # +2 for sentinel GID, +2 for num_ranges
117
+ num_ranges = read(2, 'n').first
118
+ @length += (num_ranges * RANGE_ENTRY_SIZE) + 4
119
+
120
+ ranges = Array.new(num_ranges) { read(RANGE_ENTRY_SIZE, 'nC') }
121
+
122
+ @entries = ranges.each_cons(2).map do |first, second|
123
+ first_gid, fd_index = first
124
+ second_gid, = second
125
+ [(first_gid...second_gid), fd_index]
126
+ end
127
+
128
+ # read the sentinel GID, otherwise known as the number of glyphs
129
+ # in the font
130
+ @n_glyphs = read(2, 'n').first
131
+
132
+ last_start_gid, last_fd_index = ranges.last
133
+ @entries << [(last_start_gid...(n_glyphs + 1)), last_fd_index]
134
+
135
+ @count = entries.inject(0) { |sum, entry| sum + entry.first.size }
136
+ end
137
+ end
138
+
139
+ def format_sym
140
+ case @format
141
+ when ARRAY_FORMAT then :array_format
142
+ when RANGE_FORMAT then :range_format
143
+ else
144
+ raise "unsupported fd select format '#{@format}'"
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end