ttfunk 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +74 -0
  4. data/README.md +17 -15
  5. data/lib/ttfunk/aggregate.rb +5 -0
  6. data/lib/ttfunk/bin_utils.rb +27 -8
  7. data/lib/ttfunk/bit_field.rb +25 -2
  8. data/lib/ttfunk/collection.rb +27 -3
  9. data/lib/ttfunk/directory.rb +7 -1
  10. data/lib/ttfunk/encoded_string.rb +58 -4
  11. data/lib/ttfunk/max.rb +14 -0
  12. data/lib/ttfunk/min.rb +14 -0
  13. data/lib/ttfunk/one_based_array.rb +20 -0
  14. data/lib/ttfunk/otf_encoder.rb +5 -14
  15. data/lib/ttfunk/placeholder.rb +15 -1
  16. data/lib/ttfunk/reader.rb +6 -4
  17. data/lib/ttfunk/resource_file.rb +29 -5
  18. data/lib/ttfunk/sci_form.rb +20 -3
  19. data/lib/ttfunk/sub_table.rb +29 -4
  20. data/lib/ttfunk/subset/base.rb +48 -0
  21. data/lib/ttfunk/subset/code_page.rb +49 -2
  22. data/lib/ttfunk/subset/mac_roman.rb +2 -0
  23. data/lib/ttfunk/subset/unicode.rb +32 -0
  24. data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
  25. data/lib/ttfunk/subset/windows_1252.rb +2 -0
  26. data/lib/ttfunk/subset.rb +8 -0
  27. data/lib/ttfunk/subset_collection.rb +39 -14
  28. data/lib/ttfunk/sum.rb +13 -0
  29. data/lib/ttfunk/table/cff/charset.rb +96 -18
  30. data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
  31. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
  32. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
  33. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
  34. data/lib/ttfunk/table/cff/charsets.rb +1 -0
  35. data/lib/ttfunk/table/cff/charstring.rb +33 -12
  36. data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
  37. data/lib/ttfunk/table/cff/dict.rb +53 -23
  38. data/lib/ttfunk/table/cff/encoding.rb +82 -24
  39. data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
  40. data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
  41. data/lib/ttfunk/table/cff/encodings.rb +1 -0
  42. data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
  43. data/lib/ttfunk/table/cff/font_dict.rb +30 -18
  44. data/lib/ttfunk/table/cff/font_index.rb +22 -10
  45. data/lib/ttfunk/table/cff/header.rb +16 -3
  46. data/lib/ttfunk/table/cff/index.rb +97 -65
  47. data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
  48. data/lib/ttfunk/table/cff/path.rb +43 -4
  49. data/lib/ttfunk/table/cff/private_dict.rb +31 -11
  50. data/lib/ttfunk/table/cff/subr_index.rb +7 -2
  51. data/lib/ttfunk/table/cff/top_dict.rb +82 -59
  52. data/lib/ttfunk/table/cff/top_index.rb +10 -6
  53. data/lib/ttfunk/table/cff.rb +41 -21
  54. data/lib/ttfunk/table/cmap/format00.rb +27 -6
  55. data/lib/ttfunk/table/cmap/format04.rb +34 -14
  56. data/lib/ttfunk/table/cmap/format06.rb +28 -1
  57. data/lib/ttfunk/table/cmap/format10.rb +29 -2
  58. data/lib/ttfunk/table/cmap/format12.rb +29 -2
  59. data/lib/ttfunk/table/cmap/subtable.rb +50 -6
  60. data/lib/ttfunk/table/cmap.rb +21 -0
  61. data/lib/ttfunk/table/dsig.rb +47 -6
  62. data/lib/ttfunk/table/glyf/compound.rb +73 -6
  63. data/lib/ttfunk/table/glyf/path_based.rb +40 -3
  64. data/lib/ttfunk/table/glyf/simple.rb +50 -5
  65. data/lib/ttfunk/table/glyf.rb +15 -7
  66. data/lib/ttfunk/table/head.rb +84 -6
  67. data/lib/ttfunk/table/hhea.rb +71 -10
  68. data/lib/ttfunk/table/hmtx.rb +32 -5
  69. data/lib/ttfunk/table/kern/format0.rb +25 -7
  70. data/lib/ttfunk/table/kern.rb +16 -4
  71. data/lib/ttfunk/table/loca.rb +21 -8
  72. data/lib/ttfunk/table/maxp.rb +195 -10
  73. data/lib/ttfunk/table/name.rb +126 -9
  74. data/lib/ttfunk/table/os2.rb +150 -26
  75. data/lib/ttfunk/table/post/format10.rb +7 -0
  76. data/lib/ttfunk/table/post/format20.rb +9 -0
  77. data/lib/ttfunk/table/post/format30.rb +6 -0
  78. data/lib/ttfunk/table/post/format40.rb +5 -0
  79. data/lib/ttfunk/table/post.rb +63 -7
  80. data/lib/ttfunk/table/sbix.rb +50 -14
  81. data/lib/ttfunk/table/simple.rb +5 -0
  82. data/lib/ttfunk/table/vorg.rb +31 -3
  83. data/lib/ttfunk/table.rb +20 -1
  84. data/lib/ttfunk/ttf_encoder.rb +39 -41
  85. data/lib/ttfunk.rb +154 -1
  86. data.tar.gz.sig +0 -0
  87. metadata +50 -28
  88. metadata.gz.sig +0 -0
@@ -5,44 +5,147 @@ require 'set'
5
5
 
6
6
  module TTFunk
7
7
  class Table
8
+ # OS/2 and Windows Metrics (`OS/2`) table
8
9
  class OS2 < Table
10
+ # Table version.
11
+ # @return [Integer]
9
12
  attr_reader :version
10
13
 
14
+ # Average weighted escapement.
15
+ # @return [Integer]
11
16
  attr_reader :ave_char_width
17
+
18
+ # Weight class.
19
+ # @return [Integer]
12
20
  attr_reader :weight_class
21
+
22
+ # Width class.
23
+ # @return [Integer]
13
24
  attr_reader :width_class
25
+
26
+ # Type flags.
27
+ # @return [Integer]
14
28
  attr_reader :type
29
+
30
+ # Subscript horizontal font size.
31
+ # @return [Integer]
15
32
  attr_reader :y_subscript_x_size
33
+
34
+ # Subscript vertical font size.
35
+ # @return [Integer]
16
36
  attr_reader :y_subscript_y_size
37
+
38
+ # Subscript x offset.
39
+ # @return [Integer]
17
40
  attr_reader :y_subscript_x_offset
41
+
42
+ # Subscript y offset.
43
+ # @return [Integer]
18
44
  attr_reader :y_subscript_y_offset
45
+
46
+ # Superscript horizontal font size.
47
+ # @return [Integer]
19
48
  attr_reader :y_superscript_x_size
49
+
50
+ # Superscript vertical font size.
51
+ # @return [Integer]
20
52
  attr_reader :y_superscript_y_size
53
+
54
+ # Superscript x offset.
55
+ # @return [Integer]
21
56
  attr_reader :y_superscript_x_offset
57
+
58
+ # Superscript y offset.
59
+ # @return [Integer]
22
60
  attr_reader :y_superscript_y_offset
61
+
62
+ # Strikeout size.
63
+ # @return [Integer]
23
64
  attr_reader :y_strikeout_size
65
+
66
+ # Strikeout position.
67
+ # @return [Integer]
24
68
  attr_reader :y_strikeout_position
69
+
70
+ # Font-family class and subclass.
71
+ # @return [Integer]
25
72
  attr_reader :family_class
73
+
74
+ # PANOSE classification number.
75
+ # @return [Integer]
26
76
  attr_reader :panose
77
+
78
+ # Unicode Character Range.
79
+ # @return [Integer]
27
80
  attr_reader :char_range
81
+
82
+ # Font Vendor Identification.
83
+ # @return [String]
28
84
  attr_reader :vendor_id
85
+
86
+ # Font selection flags.
87
+ # @return [Integer]
29
88
  attr_reader :selection
89
+
90
+ # The minimum Unicode index (character code) in this font.
91
+ # @return [Integer]
30
92
  attr_reader :first_char_index
93
+
94
+ # The maximum Unicode index (character code) in this font.
95
+ # @return [Integer]
31
96
  attr_reader :last_char_index
32
97
 
98
+ # The typographic ascender for this font.
99
+ # @return [Integer]
33
100
  attr_reader :ascent
101
+
102
+ # The typographic descender for this font.
103
+ # @return [Integer]
34
104
  attr_reader :descent
105
+
106
+ # The typographic line gap for this font.
107
+ # @return [Integer]
35
108
  attr_reader :line_gap
109
+
110
+ # The "Windows ascender" metric.
111
+ # @return [Integer]
36
112
  attr_reader :win_ascent
113
+
114
+ # The "Windows descender" metric.
115
+ # @return [Integer]
37
116
  attr_reader :win_descent
117
+
118
+ # Code Page Character Range.
119
+ # @return [Integer]
38
120
  attr_reader :code_page_range
39
121
 
122
+ # The distance between the baseline and the approximate height of
123
+ # non-ascending lowercase letters.
124
+ # @return [Integer]
40
125
  attr_reader :x_height
126
+
127
+ # The distance between the baseline and the approximate height of
128
+ # uppercase letters.
129
+ # @return [Integer]
41
130
  attr_reader :cap_height
131
+
132
+ # The Unicode code point, in UTF-16 encoding, of a character that can be
133
+ # used for a default glyph if a requested character is not supported in
134
+ # the font.
135
+ # @return [Integer]
42
136
  attr_reader :default_char
137
+
138
+ # The Unicode code point, in UTF-16 encoding, of a character that can be
139
+ # used as a default break character.
140
+ # @return [Integer]
43
141
  attr_reader :break_char
142
+
143
+ # The maximum length of a target glyph context for any feature in this
144
+ # font.
145
+ # @return [Integer]
44
146
  attr_reader :max_context
45
147
 
148
+ # Code page bits.
46
149
  CODE_PAGE_BITS = {
47
150
  1252 => 0,
48
151
  1250 => 1,
@@ -75,9 +178,10 @@ module TTFunk
75
178
  737 => 60,
76
179
  708 => 61,
77
180
  850 => 62,
78
- 437 => 63
181
+ 437 => 63,
79
182
  }.freeze
80
183
 
184
+ # Unicode blocks.
81
185
  UNICODE_BLOCKS = {
82
186
  (0x0000..0x007F) => 0,
83
187
  (0x0080..0x00FF) => 1,
@@ -247,17 +351,29 @@ module TTFunk
247
351
  (0x10280..0x1029F) => 121,
248
352
  (0x10920..0x1093F) => 121,
249
353
  (0x1F030..0x1F09F) => 122,
250
- (0x1F000..0x1F02F) => 122
354
+ (0x1F000..0x1F02F) => 122,
251
355
  }.freeze
252
356
 
357
+ # Indicates that font supports supplementary characters.
253
358
  UNICODE_MAX = 0xFFFF
254
- UNICODE_RANGES = UNICODE_BLOCKS.keys.freeze
359
+
360
+ # Unicode block ranges.
361
+ UNICODE_RANGES = UNICODE_BLOCKS.keys.sort_by(&:max).freeze
362
+
363
+ # Start chracter for average character width calculation.
255
364
  LOWERCASE_START = 'a'.ord
365
+
366
+ # End chracter for average character width calculation.
256
367
  LOWERCASE_END = 'z'.ord
368
+
369
+ # Number of chracters for average character width calculation.
257
370
  LOWERCASE_COUNT = (LOWERCASE_END - LOWERCASE_START) + 1
371
+
372
+ # Space character code point.
258
373
  CODEPOINT_SPACE = 32
259
- SPACE_GLYPH_MISSING_ERROR = "Space glyph (0x#{CODEPOINT_SPACE.to_s(16)})"\
260
- ' must be included in the font'
374
+
375
+ # Error message for missing space character.
376
+ SPACE_GLYPH_MISSING_ERROR = "Space glyph (0x#{CODEPOINT_SPACE.to_s(16)}) must be included in the font"
261
377
 
262
378
  # Used to calculate the xAvgCharWidth field.
263
379
  # From https://docs.microsoft.com/en-us/typography/opentype/spec/os2:
@@ -272,16 +388,26 @@ module TTFunk
272
388
  # 26 letters in the Latin alphabet. Each weight is the relative
273
389
  # frequency of that letter in the English language.
274
390
  WEIGHT_SPACE = 166
391
+
392
+ # chracter weights for average character width calculation.
275
393
  WEIGHT_LOWERCASE = [
276
394
  64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20,
277
- 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2
395
+ 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2,
278
396
  ].freeze
279
397
 
398
+ # Table tag.
399
+ # @return [String]
280
400
  def tag
281
401
  'OS/2'
282
402
  end
283
403
 
284
404
  class << self
405
+ # Encode table.
406
+ #
407
+ # @param os2 [TTFunk::Table::OS2]
408
+ # @param subset [TTFunk::Subset::MacRoman, TTFunk::Subset::Windows1252,
409
+ # TTFunk::Subset::Unicode, TTFunk::Subset::Unicode8Bit]
410
+ # @return [String]
285
411
  def encode(os2, subset)
286
412
  result = ''.b
287
413
  result << [
@@ -291,7 +417,7 @@ module TTFunk
291
417
  os2.y_subscript_y_offset, os2.y_superscript_x_size,
292
418
  os2.y_superscript_y_size, os2.y_superscript_x_offset,
293
419
  os2.y_superscript_y_offset, os2.y_strikeout_size,
294
- os2.y_strikeout_position, os2.family_class
420
+ os2.y_strikeout_position, os2.family_class,
295
421
  ].pack('n*')
296
422
 
297
423
  result << os2.panose
@@ -301,7 +427,7 @@ module TTFunk
301
427
  .slice_int(
302
428
  new_char_range.value,
303
429
  bit_width: 32,
304
- slice_count: 4
430
+ slice_count: 4,
305
431
  )
306
432
  .pack('N*')
307
433
 
@@ -322,27 +448,27 @@ module TTFunk
322
448
  last_char_index = [code_points.last || 0, UNICODE_MAX].min
323
449
 
324
450
  result << [
325
- os2.selection, first_char_index, last_char_index
451
+ os2.selection, first_char_index, last_char_index,
326
452
  ].pack('n*')
327
453
 
328
454
  if os2.version.positive?
329
455
  result << [
330
456
  os2.ascent, os2.descent, os2.line_gap,
331
- os2.win_ascent, os2.win_descent
457
+ os2.win_ascent, os2.win_descent,
332
458
  ].pack('n*')
333
459
 
334
460
  result << BinUtils
335
461
  .slice_int(
336
462
  code_pages_for(subset).value,
337
463
  bit_width: 32,
338
- slice_count: 2
464
+ slice_count: 2,
339
465
  )
340
466
  .pack('N*')
341
467
 
342
468
  if os2.version > 1
343
469
  result << [
344
470
  os2.x_height, os2.cap_height, os2.default_char,
345
- os2.break_char, os2.max_context
471
+ os2.break_char, os2.max_context,
346
472
  ].pack('n*')
347
473
  end
348
474
  end
@@ -380,13 +506,15 @@ module TTFunk
380
506
 
381
507
  def group_original_code_points_by_bit(os2)
382
508
  Hash.new { |h, k| h[k] = [] }.tap do |result|
383
- os2.file.cmap.unicode.first.code_map.each_key do |code_point|
384
- # find corresponding bit
385
- range = UNICODE_RANGES.find { |r| r.cover?(code_point) }
386
-
387
- if (bit = UNICODE_BLOCKS[range])
388
- result[bit] << code_point
509
+ code_points = os2.file.cmap.unicode.first.code_map.keys.sort
510
+ UNICODE_RANGES.each do |r|
511
+ code_points = code_points.drop_while { |p| p < r.min }
512
+ code_points.take_while { |p| p <= r.max }.each do |code_point|
513
+ if (bit = UNICODE_BLOCKS[r])
514
+ result[bit] << code_point
515
+ end
389
516
  end
517
+ code_points = code_points.drop_while { |p| p <= r.max }
390
518
  end
391
519
  end
392
520
  end
@@ -405,7 +533,7 @@ module TTFunk
405
533
 
406
534
  # use new -> old glyph mapping in order to include compound glyphs
407
535
  # in the calculation
408
- subset.new_to_old_glyph.each do |_, old_gid|
536
+ subset.new_to_old_glyph.each_value do |old_gid|
409
537
  if (metric = os2.file.horizontal_metrics.for(old_gid))
410
538
  total_width += metric.advance_width
411
539
  num_glyphs += 1 if metric.advance_width.positive?
@@ -456,7 +584,7 @@ module TTFunk
456
584
 
457
585
  # use new -> old glyph mapping in order to include compound glyphs
458
586
  # in the calculation
459
- subset.new_to_old_glyph.each do |_, old_gid|
587
+ subset.new_to_old_glyph.each_value do |old_gid|
460
588
  if (metric = os2.file.horizontal_metrics.for(old_gid))
461
589
  total_width += metric.advance_width
462
590
  end
@@ -481,9 +609,7 @@ module TTFunk
481
609
  @y_strikeout_position, @family_class = read_signed(12)
482
610
  @panose = io.read(10)
483
611
 
484
- @char_range = BitField.new(
485
- BinUtils.stitch_int(read(16, 'N*'), bit_width: 32)
486
- )
612
+ @char_range = BitField.new(BinUtils.stitch_int(read(16, 'N*'), bit_width: 32))
487
613
 
488
614
  @vendor_id = io.read(4)
489
615
  @selection, @first_char_index, @last_char_index = read(6, 'n*')
@@ -491,9 +617,7 @@ module TTFunk
491
617
  if @version.positive?
492
618
  @ascent, @descent, @line_gap = read_signed(3)
493
619
  @win_ascent, @win_descent = read(4, 'nn')
494
- @code_page_range = BitField.new(
495
- BinUtils.stitch_int(read(8, 'N*'), bit_width: 32)
496
- )
620
+ @code_page_range = BitField.new(BinUtils.stitch_int(read(8, 'N*'), bit_width: 32))
497
621
 
498
622
  if @version > 1
499
623
  @x_height, @cap_height = read_signed(2)
@@ -3,7 +3,10 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 1.0 provides glyph names for standard 258 glyphs in the standard
7
+ # Macintosh TrueType font file.
6
8
  module Format10
9
+ # Glyph names.
7
10
  POSTSCRIPT_GLYPHS = %w[
8
11
  .notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar
9
12
  percent ampersand quotesingle parenleft parenright asterisk plus comma
@@ -36,6 +39,10 @@ module TTFunk
36
39
  scedilla Cacute cacute Ccaron ccaron dcroat
37
40
  ].freeze
38
41
 
42
+ # Get glyph name for character code.
43
+ #
44
+ # @param code [Integer]
45
+ # @return [String]
39
46
  def glyph_for(code)
40
47
  POSTSCRIPT_GLYPHS[code] || '.notdef'
41
48
  end
@@ -6,9 +6,18 @@ require 'stringio'
6
6
  module TTFunk
7
7
  class Table
8
8
  class Post
9
+ # Version 2.0 is used for fonts that use glyph names that are not in the
10
+ # set of Macintosh glyph names. A given font may map some of its glyphs to
11
+ # the standard Macintosh glyph names, and some to its own custom names.
12
+ # A version 2.0 `post` table can be used in fonts with TrueType or CFF
13
+ # version 2 outlines.
9
14
  module Format20
10
15
  include Format10
11
16
 
17
+ # Get glyph name for character code.
18
+ #
19
+ # @param code [Integer]
20
+ # @return [String]
12
21
  def glyph_for(code)
13
22
  index = @glyph_name_index[code]
14
23
  return '.notdef' unless index
@@ -3,7 +3,13 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 3.0 specifies that no PostScript name information is provided
7
+ # for the glyphs in this font file.
6
8
  module Format30
9
+ # Get glyph name for character code.
10
+ #
11
+ # @param _code [Integer]
12
+ # @return [String]
7
13
  def glyph_for(_code)
8
14
  '.notdef'
9
15
  end
@@ -3,7 +3,12 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Post
6
+ # Version 4.0 names glyphs by their character code.
6
7
  module Format40
8
+ # Get glyph name for character code.
9
+ #
10
+ # @param code [Integer]
11
+ # @return [String]
7
12
  def glyph_for(code)
8
13
  @map[code] || 0xFFFF
9
14
  end
@@ -4,33 +4,93 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # PostScript (`post`) table.
8
+ #
9
+ # This class can be extended with version-specific modules.
10
+ #
11
+ # @see TTFunk::Table::Post::Format10
12
+ # @see TTFunk::Table::Post::Format20
13
+ # @see TTFunk::Table::Post::Format30
14
+ # @see TTFunk::Table::Post::Format40
7
15
  class Post < Table
16
+ # Table version.
17
+ # @return [Integer]
8
18
  attr_reader :format
19
+
20
+ # Italic angle in counter-clockwise degrees from the vertical.
21
+ # @return [Integer]
9
22
  attr_reader :italic_angle
23
+
24
+ # Suggested distance of the top of the underline from the baseline
25
+ # @return [Integer]
10
26
  attr_reader :underline_position
27
+
28
+ # Suggested values for the underline thickness.
29
+ # @return [Integer]
11
30
  attr_reader :underline_thickness
31
+
32
+ # 0 if the font is proportionally spaced, non-zero if the font is not
33
+ # proportionally spaced.
34
+ # @return [Integer]
12
35
  attr_reader :fixed_pitch
36
+
37
+ # Minimum memory usage when an OpenType font is downloaded.
38
+ # @return [Integer]
13
39
  attr_reader :min_mem_type42
40
+
41
+ # Maximum memory usage when an OpenType font is downloaded.
42
+ # @return [Integer]
14
43
  attr_reader :max_mem_type42
44
+
45
+ # Minimum memory usage when an OpenType font is downloaded as
46
+ # a Type 1 font.
47
+ # @return [Integer]
15
48
  attr_reader :min_mem_type1
49
+
50
+ # Maximum memory usage when an OpenType font is downloaded as
51
+ # a Type 1 font.
52
+ # @return [Integer]
16
53
  attr_reader :max_mem_type1
17
54
 
55
+ # Version-specific fields.
56
+ # @return [TTFunk::Table::Post::Format10, TTFunk::Table::Post::Format20,
57
+ # TTFunk::Table::Post::Format30, TTFunk::Table::Post::Format40]
18
58
  attr_reader :subtable
19
59
 
60
+ # Encode table.
61
+ #
62
+ # @param post [TTFunk::Table::Post]
63
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
64
+ # are old glyph IDs
65
+ # @return [String, nil]
20
66
  def self.encode(post, mapping)
21
- return unless post.exists?
67
+ return if post.nil?
22
68
 
23
69
  post.recode(mapping)
24
70
  end
25
71
 
72
+ # Is this font monospaced?
73
+ #
74
+ # @return [Boolean]
26
75
  def fixed_pitch?
27
76
  @fixed_pitch != 0
28
77
  end
29
78
 
79
+ # Get glyph name for character code.
80
+ #
81
+ # This is a placeholder.
82
+ #
83
+ # @param _code [Integer]
84
+ # @return [String]
30
85
  def glyph_for(_code)
31
86
  '.notdef'
32
87
  end
33
88
 
89
+ # Re-encode this table.
90
+ #
91
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
92
+ # are old glyph IDs
93
+ # @return [String]
34
94
  def recode(mapping)
35
95
  return raw if format == 0x00030000
36
96
 
@@ -46,7 +106,7 @@ module TTFunk
46
106
  if position
47
107
  index << position
48
108
  else
49
- index << 257 + strings.length
109
+ index << (257 + strings.length)
50
110
  strings << post_glyph
51
111
  end
52
112
  end
@@ -85,11 +145,7 @@ module TTFunk
85
145
  end
86
146
 
87
147
  def parse_format!
88
- warn(
89
- Kernel.format(
90
- 'postscript table format 0x%08X is not supported', @format
91
- )
92
- )
148
+ warn(Kernel.format('postscript table format 0x%08X is not supported', @format))
93
149
  end
94
150
  end
95
151
  end
@@ -4,14 +4,48 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Standard Bitmap Graphics (`sbix`) table.
7
8
  class Sbix < Table
9
+ # Table version.
10
+ # @return [Integer]
8
11
  attr_reader :version
12
+
13
+ # Flags.
14
+ # @return [Integer]
9
15
  attr_reader :flags
16
+
17
+ # Number of bitmap strikes.
18
+ # @return [Integer]
10
19
  attr_reader :num_strikes
20
+
21
+ # Strikes.
22
+ # @return [Array<Hash>]
11
23
  attr_reader :strikes
12
24
 
25
+ # Bitmap Data.
26
+ #
27
+ # @!attribute [rw] x
28
+ # The horizontal (x-axis) position of the left edge of the bitmap
29
+ # graphic in relation to the glyph design space origin.
30
+ # @!attribute [rw] y
31
+ # The vertical (y-axis) position of the bottom edge of the bitmap
32
+ # graphic in relation to the glyph design space origin.
33
+ # @!attribute [rw] type
34
+ # Indicates the format of the embedded graphic data: one of `jpg `,
35
+ # `png `, `tiff`, or the special format `dupe`.
36
+ # @!attribute [rw] data
37
+ # The actual embedded graphic data.
38
+ # @!attribute [rw] ppem
39
+ # The PPEM size for which this strike was designed.
40
+ # @!attribute [rw] resolution
41
+ # The device pixel density (in PPI) for which this strike was designed.
13
42
  BitmapData = Struct.new(:x, :y, :type, :data, :ppem, :resolution)
14
43
 
44
+ # Get bitmap for glyph strike.
45
+ #
46
+ # @param glyph_id [Integer]
47
+ # @param strike_index [Integer]
48
+ # @return [BitmapData]
15
49
  def bitmap_data_for(glyph_id, strike_index)
16
50
  strike = strikes[strike_index]
17
51
  return if strike.nil?
@@ -22,21 +56,23 @@ module TTFunk
22
56
  if glyph_offset && next_glyph_offset
23
57
  bytes = next_glyph_offset - glyph_offset
24
58
  if bytes.positive?
25
- parse_from(offset + strike[:offset] + glyph_offset) do
59
+ parse_from(offset + strike[:offset] + glyph_offset) {
26
60
  x, y, type = read(8, 's2A4')
27
61
  data = StringIO.new(io.read(bytes - 8))
28
- BitmapData.new(
29
- x, y, type, data, strike[:ppem], strike[:resolution]
30
- )
31
- end
62
+ BitmapData.new(x, y, type, data, strike[:ppem], strike[:resolution])
63
+ }
32
64
  end
33
65
  end
34
66
  end
35
67
 
68
+ # Get all bitmaps for glyph.
69
+ #
70
+ # @param glyph_id [Integer]
71
+ # @return [Array<BitmapData>]
36
72
  def all_bitmap_data_for(glyph_id)
37
- strikes.each_index.map do |strike_index|
73
+ strikes.each_index.filter_map { |strike_index|
38
74
  bitmap_data_for(glyph_id, strike_index)
39
- end.compact
75
+ }
40
76
  end
41
77
 
42
78
  private
@@ -46,21 +82,21 @@ module TTFunk
46
82
  strike_offsets = Array.new(num_strikes) { read(4, 'N').first }
47
83
 
48
84
  @strikes =
49
- strike_offsets.map do |strike_offset|
50
- parse_from(offset + strike_offset) do
85
+ strike_offsets.map { |strike_offset|
86
+ parse_from(offset + strike_offset) {
51
87
  ppem, resolution = read(4, 'n2')
52
88
  data_offsets =
53
- Array.new(file.maximum_profile.num_glyphs + 1) do
89
+ Array.new(file.maximum_profile.num_glyphs + 1) {
54
90
  read(4, 'N').first
55
- end
91
+ }
56
92
  {
57
93
  ppem: ppem,
58
94
  resolution: resolution,
59
95
  offset: strike_offset,
60
- glyph_data_offset: data_offsets
96
+ glyph_data_offset: data_offsets,
61
97
  }
62
- end
63
- end
98
+ }
99
+ }
64
100
  end
65
101
  end
66
102
  end
@@ -4,9 +4,14 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # A table that TTFunk doesn't decode but preserve.
7
8
  class Simple < Table
9
+ # Table tag
10
+ # @return [String]
8
11
  attr_reader :tag
9
12
 
13
+ # @param file [TTFunk::File]
14
+ # @param tag [String]
10
15
  def initialize(file, tag)
11
16
  @tag = tag
12
17
  super(file)