fontisan 0.2.13 → 0.2.14

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.
@@ -327,7 +327,10 @@ module Fontisan
327
327
 
328
328
  # Get CharStrings INDEX from CFF
329
329
  charstrings_index = cff_table.charstrings_index(0)
330
- raise Fontisan::Error, "CharStrings INDEX not found" unless charstrings_index
330
+ unless charstrings_index
331
+ raise Fontisan::Error,
332
+ "CharStrings INDEX not found"
333
+ end
331
334
 
332
335
  # Get Private DICT for context
333
336
  private_dict = cff_table.private_dict(0)
@@ -335,7 +338,7 @@ module Fontisan
335
338
  # Create CFF to Type 1 converter
336
339
  converter = Type1::CffToType1Converter.new(
337
340
  nominal_width: private_dict&.nominal_width || 0,
338
- default_width: private_dict&.default_width || 0
341
+ default_width: private_dict&.default_width || 0,
339
342
  )
340
343
 
341
344
  # Convert each CFF CharString to Type 1 format
@@ -354,7 +357,7 @@ module Fontisan
354
357
  private_dict_hash = build_private_dict_hash(private_dict)
355
358
  type1_charstrings[glyph_name] = converter.convert(
356
359
  cff_charstring,
357
- private_dict: private_dict_hash
360
+ private_dict: private_dict_hash,
358
361
  )
359
362
  end
360
363
 
@@ -551,7 +554,7 @@ module Fontisan
551
554
  # Parse version (e.g., "001.000" => 1.0)
552
555
  version_parts = version_str.split(".")
553
556
  major = version_parts[0].to_i
554
- minor = version_parts[1]&.to_i || 0
557
+ minor = version_parts[1].to_i
555
558
  version = major + (minor / 1000.0)
556
559
 
557
560
  # Version (Fixed 16.16) - stored as int32
@@ -626,24 +629,24 @@ module Fontisan
626
629
 
627
630
  # Ascent (int16) - Distance from baseline to highest ascender
628
631
  # Use BlueValues[2] or [3] if available, otherwise font_bbox[3]
629
- if blue_values.length >= 4
630
- ascent = blue_values[3] # Top zone top
631
- elsif blue_values.length >= 3
632
- ascent = blue_values[2] # Top zone bottom
633
- else
634
- ascent = font_bbox[3] # y_max
635
- end
632
+ ascent = if blue_values.length >= 4
633
+ blue_values[3] # Top zone top
634
+ elsif blue_values.length >= 3
635
+ blue_values[2] # Top zone bottom
636
+ else
637
+ font_bbox[3] # y_max
638
+ end
636
639
  data << [ascent].pack("s>")
637
640
 
638
641
  # Descent (int16) - Distance from baseline to lowest descender (negative)
639
642
  # Use BlueValues[0] or [1] if available, otherwise font_bbox[1]
640
- if blue_values.length >= 2
641
- descent = blue_values[0] # Bottom zone bottom (negative)
642
- elsif blue_values.length >= 1
643
- descent = blue_values[0]
644
- else
645
- descent = font_bbox[1] # y_min (should be negative)
646
- end
643
+ descent = if blue_values.length >= 2
644
+ blue_values[0] # Bottom zone bottom (negative)
645
+ elsif blue_values.length >= 1
646
+ blue_values[0]
647
+ else
648
+ font_bbox[1] # y_min (should be negative)
649
+ end
647
650
  data << [descent].pack("s>")
648
651
 
649
652
  # Line Gap (int16) - Additional space between lines
@@ -728,33 +731,33 @@ module Fontisan
728
731
 
729
732
  # Extract font names with fallbacks
730
733
  font_name = font.font_name || font_dict&.font_name || "Unnamed"
731
- family_name = if font_info&.respond_to?(:family_name)
734
+ family_name = if font_info.respond_to?(:family_name)
732
735
  font_info.family_name || font_dict&.family_name || font_name
733
736
  else
734
737
  font_dict&.family_name || font_name
735
738
  end
736
- full_name = if font_info&.respond_to?(:full_name)
739
+ full_name = if font_info.respond_to?(:full_name)
737
740
  font_info.full_name || font_dict&.full_name || family_name
738
741
  else
739
742
  font_dict&.full_name || family_name
740
743
  end
741
- version = if font_info&.respond_to?(:version)
744
+ version = if font_info.respond_to?(:version)
742
745
  font_info.version || font.version || "001.000"
743
746
  else
744
747
  font.version || "001.000"
745
748
  end
746
- copyright = if font_info&.respond_to?(:copyright)
747
- font_info.copyright || font_dict&.raw_data&.dig(:copyright) || ""
748
- else
749
- font_dict&.raw_data&.dig(:copyright) || ""
750
- end
749
+ copyright = if font_info.respond_to?(:copyright)
750
+ font_info.copyright || font_dict&.raw_data&.dig(:copyright) || ""
751
+ else
752
+ font_dict&.raw_data&.dig(:copyright) || ""
753
+ end
751
754
  postscript_name = font_name
752
- weight = if font_info&.respond_to?(:weight)
755
+ weight = if font_info.respond_to?(:weight)
753
756
  font_info.weight
754
757
  else
755
758
  "Regular"
756
759
  end
757
- notice = if font_info&.respond_to?(:notice)
760
+ notice = if font_info.respond_to?(:notice)
758
761
  font_info.notice
759
762
  else
760
763
  ""
@@ -782,7 +785,9 @@ module Fontisan
782
785
  ]
783
786
 
784
787
  # Filter out empty strings and build string storage
785
- name_records = name_records.select { |r| !r[:string].nil? && !r[:string].empty? }
788
+ name_records = name_records.select do |r|
789
+ !r[:string].nil? && !r[:string].empty?
790
+ end
786
791
 
787
792
  # Build string storage (UTF-16BE encoded for Windows platform)
788
793
  string_storage = (+"").b
@@ -810,15 +815,15 @@ module Fontisan
810
815
  # Write name records
811
816
  platform_id = 3 # Windows
812
817
  encoding_id = 1 # Unicode BMP
813
- language_id = 0x0409 # US English
818
+ language_id = 0x0409 # US English
814
819
 
815
820
  name_records.each do |record|
816
821
  data << [platform_id].pack("n") # platform ID
817
822
  data << [encoding_id].pack("n") # encoding ID
818
823
  data << [language_id].pack("n") # language ID
819
824
  data << [record[:name_id]].pack("n") # name ID
820
- data << [record[:encoded].bytesize].pack("n") # string length
821
- data << [record[:offset]].pack("n") # string offset
825
+ data << [record[:encoded].bytesize].pack("n") # string length
826
+ data << [record[:offset]].pack("n") # string offset
822
827
  end
823
828
 
824
829
  # Write string storage
@@ -926,13 +931,13 @@ module Fontisan
926
931
 
927
932
  # Unicode ranges (4 x uint32) - Basic Latin + Latin-1
928
933
  # Bits 0-31: Basic Latin, Latin-1, Latin Extended-A/B, etc.
929
- data << [0x00000001].pack("N") # Basic Latin (0-7F)
934
+ data << [0x00000001].pack("N") # Basic Latin (0-7F)
930
935
  data << [0x00000000].pack("N")
931
936
  data << [0x00000000].pack("N")
932
937
  data << [0x00000000].pack("N")
933
938
 
934
939
  # achVendID (4 bytes) - Vendor ID
935
- data << "UKWN" # Unknown
940
+ data << "UKWN" # Unknown
936
941
 
937
942
  # fsSelection (uint16) - Font selection flags
938
943
  # Bit 6 (0x40) = Regular weight if 400-500
@@ -946,25 +951,25 @@ module Fontisan
946
951
  data << [fs_selection].pack("n")
947
952
 
948
953
  # usFirstCharIndex (uint16) - First Unicode character
949
- data << [32].pack("n") # Space
954
+ data << [32].pack("n") # Space
950
955
 
951
956
  # usLastCharIndex (uint16) - Last Unicode character
952
- data << [0xFFFD].pack("n") # Replacement character
957
+ data << [0xFFFD].pack("n") # Replacement character
953
958
 
954
959
  # sTypoAscender (int16) - Use BlueValues or font bbox
955
- if blue_values.length >= 4
956
- typo_ascender = blue_values[3]
957
- else
958
- typo_ascender = font_bbox[3]
959
- end
960
+ typo_ascender = if blue_values.length >= 4
961
+ blue_values[3]
962
+ else
963
+ font_bbox[3]
964
+ end
960
965
  data << [typo_ascender].pack("s>")
961
966
 
962
967
  # sTypoDescender (int16) - Use BlueValues or font bbox (negative)
963
- if blue_values.length >= 2
964
- typo_descender = blue_values[0]
965
- else
966
- typo_descender = font_bbox[1]
967
- end
968
+ typo_descender = if blue_values.length >= 2
969
+ blue_values[0]
970
+ else
971
+ font_bbox[1]
972
+ end
968
973
  data << [typo_descender].pack("s>")
969
974
 
970
975
  # sTypoLineGap (int16)
@@ -1013,7 +1018,7 @@ module Fontisan
1013
1018
  # Version (Fixed 16.16) - Use version 3.0 for CFF fonts (no glyph names)
1014
1019
  # Version 2.0 would include glyph names, but for OTF output version 3.0 is fine
1015
1020
  # since CFF table contains the glyph names
1016
- data << [0x00030000].pack("N") # Version 3.0
1021
+ data << [0x00030000].pack("N") # Version 3.0
1017
1022
 
1018
1023
  # Italic Angle (Fixed 16.16)
1019
1024
  # Get from FontInfo if available, otherwise default to 0
@@ -1030,7 +1035,7 @@ module Fontisan
1030
1035
  data << [underline_thickness].pack("s>")
1031
1036
 
1032
1037
  # Fixed Pitch (uint32) - Boolean for monospace
1033
- is_fixed_pitch = (font_info.is_fixed_pitch || false) ? 1 : 0
1038
+ is_fixed_pitch = font_info.is_fixed_pitch || false ? 1 : 0
1034
1039
  data << [is_fixed_pitch].pack("N")
1035
1040
 
1036
1041
  # Min/Max Memory for Type 42 (uint32 each) - Not used for CFF, set to 0
@@ -1066,10 +1071,10 @@ module Fontisan
1066
1071
  unicode = Type1::AGL.unicode_for_glyph_name(glyph_name)
1067
1072
 
1068
1073
  # If no Unicode mapping, try to derive from encoding position
1069
- if unicode.nil?
1074
+ if unicode.nil? && (glyph_index < 128)
1070
1075
  # For standard encoding, try to map from position
1071
1076
  # This is a simplified approach - real implementation would be more robust
1072
- unicode = glyph_index if glyph_index < 128
1077
+ unicode = glyph_index
1073
1078
  end
1074
1079
 
1075
1080
  # Map Unicode to glyph index
@@ -1088,21 +1093,21 @@ module Fontisan
1088
1093
  subtable_data = build_cmap_format_4(unicode_to_glyph)
1089
1094
 
1090
1095
  # Calculate offsets
1091
- encoding_records_offset = 4 # After version (2) + num_tables (2)
1092
- subtable_offset = encoding_records_offset + 8 # After one encoding record (8 bytes)
1096
+ encoding_records_offset = 4 # After version (2) + num_tables (2)
1097
+ subtable_offset = encoding_records_offset + 8 # After one encoding record (8 bytes)
1093
1098
 
1094
1099
  # Build cmap table header
1095
1100
  # Version (uint16)
1096
1101
  data << [0].pack("n")
1097
1102
 
1098
1103
  # Number of encoding records (uint16)
1099
- data << [1].pack("n") # One encoding record
1104
+ data << [1].pack("n") # One encoding record
1100
1105
 
1101
1106
  # Encoding record: Platform ID (uint16), Encoding ID (uint16), Subtable offset (uint32)
1102
1107
  # Platform 3 (Windows), Encoding 1 (Unicode BMP)
1103
1108
  data << [3].pack("n") # Platform ID: Windows
1104
1109
  data << [1].pack("n") # Encoding ID: Unicode BMP
1105
- data << [subtable_offset].pack("N") # Subtable offset
1110
+ data << [subtable_offset].pack("N") # Subtable offset
1106
1111
 
1107
1112
  # Append subtable data
1108
1113
  data << subtable_data
@@ -1160,13 +1165,13 @@ module Fontisan
1160
1165
  # Calculate segment count and related values
1161
1166
  seg_count = segments.length
1162
1167
  seg_count_x2 = seg_count * 2
1163
- search_range = 2 ** (Math.log2(seg_count).to_i) * 2
1168
+ search_range = 2**Math.log2(seg_count).to_i * 2
1164
1169
  entry_selector = Math.log2(search_range / 2).to_i
1165
1170
  range_shift = (seg_count - search_range / 2) * 2
1166
1171
 
1167
1172
  # Build format 4 subtable header (14 bytes)
1168
- data << [4].pack("n") # Format
1169
- data << [calculate_cmap4_length(segments)].pack("n") # Length (placeholder)
1173
+ data << [4].pack("n") # Format
1174
+ data << [calculate_cmap4_length(segments)].pack("n") # Length (placeholder)
1170
1175
  data << [0].pack("n") # Language (0 = independent)
1171
1176
  data << [seg_count_x2].pack("n") # segCountX2
1172
1177
  data << [search_range].pack("n") # searchRange
@@ -1203,9 +1208,9 @@ module Fontisan
1203
1208
 
1204
1209
  # Write arrays (padded to even length)
1205
1210
  end_codes.each { |code| data << [code].pack("n") }
1206
- data << [0].pack("n") # Reserved padding
1211
+ data << [0].pack("n") # Reserved padding
1207
1212
  start_codes.each { |code| data << [code].pack("n") }
1208
- id_deltas.each { |delta| data << [delta].pack("s>") } # Signed
1213
+ id_deltas.each { |delta| data << [delta].pack("s>") } # Signed
1209
1214
  id_range_offsets.each { |offset| data << [offset].pack("n") }
1210
1215
  glyph_id_array.each { |gid| data << [gid].pack("n") }
1211
1216
 
@@ -1227,7 +1232,7 @@ module Fontisan
1227
1232
  seg_count = segments.length
1228
1233
 
1229
1234
  # Rough estimate (actual calculation done during construction)
1230
- 14 + (seg_count * 8) + (seg_count * 2) + 100 # 100 for glyph ID array estimate
1235
+ 14 + (seg_count * 8) + (seg_count * 2) + 100 # 100 for glyph ID array estimate
1231
1236
  end
1232
1237
  end
1233
1238
  end
@@ -276,7 +276,8 @@ module Fontisan
276
276
  # Merge all extracted hints (prep_hints and fpgm_hints override stem widths if present)
277
277
  # Note: fpgm_hints contains metadata (fpgm_size, has_functions, complexity)
278
278
  # which we must filter out before merging into PostScript dict hints
279
- fpgm_dict_hints = fpgm_hints.reject { |k, _| %i[fpgm_size has_functions complexity].include?(k) }
279
+ fpgm_dict_hints = fpgm_hints.except(:fpgm_size, :has_functions,
280
+ :complexity)
280
281
  hints.merge!(prep_hints).merge!(fpgm_dict_hints).merge!(blue_zones)
281
282
 
282
283
  # Provide default blue_values if none were detected
@@ -32,46 +32,6 @@ module Fontisan
32
32
  # Page size for lazy loading alignment (typical filesystem page size)
33
33
  PAGE_SIZE = 4096
34
34
 
35
- # Read OpenType Font from a file
36
- #
37
- # @param path [String] Path to the OTF file
38
- # @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
39
- # @param lazy [Boolean] If true, load tables on demand (default: false)
40
- # @return [OpenTypeFont] A new instance
41
- # @raise [ArgumentError] if path is nil or empty, or if mode is invalid
42
- # @raise [Errno::ENOENT] if file does not exist
43
- # @raise [RuntimeError] if file format is invalid
44
- def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
45
- if path.nil? || path.to_s.empty?
46
- raise ArgumentError,
47
- "path cannot be nil or empty"
48
- end
49
- raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
50
-
51
- # Validate mode
52
- LoadingModes.validate_mode!(mode)
53
-
54
- File.open(path, "rb") do |io|
55
- font = read(io)
56
- font.initialize_storage
57
- font.loading_mode = mode
58
- font.lazy_load_enabled = lazy
59
-
60
- if lazy
61
- # Keep file handle open for lazy loading
62
- font.io_source = File.open(path, "rb")
63
- font.setup_finalizer
64
- else
65
- # Read tables upfront
66
- font.read_table_data(io)
67
- end
68
-
69
- font
70
- end
71
- rescue BinData::ValidityError, EOFError => e
72
- raise "Invalid OTF file: #{e.message}"
73
- end
74
-
75
35
  # Initialize storage hashes
76
36
  #
77
37
  # Extends base class to add page_cache for lazy loading.
@@ -149,34 +149,52 @@ module Fontisan
149
149
  # @raise [RuntimeError] if file format is invalid
150
150
  def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
151
151
  if path.nil? || path.to_s.empty?
152
- raise ArgumentError,
153
- "path cannot be nil or empty"
152
+ raise ArgumentError, "path cannot be nil or empty"
154
153
  end
155
154
  raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
156
155
 
157
- # Validate mode
158
156
  LoadingModes.validate_mode!(mode)
159
157
 
160
- File.open(path, "rb") do |io|
161
- font = read(io)
162
- font.initialize_storage
163
- font.loading_mode = mode
164
- font.lazy_load_enabled = lazy
165
-
166
- if lazy
167
- # Keep file handle open for lazy loading
168
- font.io_source = File.open(path, "rb")
169
- font.setup_finalizer
170
- else
171
- # Read tables upfront
172
- font.read_table_data(io)
173
- end
158
+ font = new
159
+ font.initialize_storage
160
+ font.loading_mode = mode
161
+ font.lazy_load_enabled = lazy
174
162
 
175
- font
163
+ lazy ? load_lazy(path, font) : load_eager(path, font)
164
+ end
165
+
166
+ # Load font with lazy loading (keeps file handle open)
167
+ #
168
+ # @param path [String] Path to the font file
169
+ # @param font [SfntFont] Font instance to populate
170
+ # @return [SfntFont] The populated font instance
171
+ def self.load_lazy(path, font)
172
+ font.io_source = File.open(path, "rb")
173
+ font.setup_finalizer
174
+ font.io_source.rewind
175
+ font.read(font.io_source)
176
+ font
177
+ rescue BinData::ValidityError, EOFError => e
178
+ font_type = name.split("::").last
179
+ raise "Invalid #{font_type} file: #{e.message}"
180
+ end
181
+
182
+ # Load font with eager loading (reads all data, closes file)
183
+ #
184
+ # @param path [String] Path to the font file
185
+ # @param font [SfntFont] Font instance to populate
186
+ # @return [SfntFont] The populated font instance
187
+ def self.load_eager(path, font)
188
+ File.open(path, "rb") do |io|
189
+ font.read(io)
190
+ font.read_table_data(io)
176
191
  end
192
+ font
177
193
  rescue BinData::ValidityError, EOFError => e
178
- raise "Invalid font file: #{e.message}"
194
+ font_type = name.split("::").last
195
+ raise "Invalid #{font_type} file: #{e.message}"
179
196
  end
197
+ private_class_method :load_lazy, :load_eager
180
198
 
181
199
  # Read SFNT Font from collection at specific offset
182
200
  #
@@ -32,7 +32,7 @@ module Fontisan
32
32
 
33
33
  # Get a single font from the collection
34
34
  #
35
- # Overrides BaseCollection to use TrueType-specific from_ttc method.
35
+ # Uses the base class from_collection method.
36
36
  #
37
37
  # @param index [Integer] Index of the font (0-based)
38
38
  # @param io [IO] Open file handle
@@ -42,13 +42,13 @@ module Fontisan
42
42
  return nil if index >= num_fonts
43
43
 
44
44
  require_relative "true_type_font"
45
- TrueTypeFont.from_ttc(io, font_offsets[index], mode: mode)
45
+ TrueTypeFont.from_collection(io, font_offsets[index], mode: mode)
46
46
  end
47
47
 
48
48
  # Extract fonts as TrueTypeFont objects
49
49
  #
50
50
  # Reads each font from the TTC file and returns them as TrueTypeFont objects.
51
- # This method uses the TTC-specific from_ttc method.
51
+ # Uses the base class from_collection method.
52
52
  #
53
53
  # @param io [IO] Open file handle to read fonts from
54
54
  # @return [Array<TrueTypeFont>] Array of font objects
@@ -56,13 +56,13 @@ module Fontisan
56
56
  require_relative "true_type_font"
57
57
 
58
58
  font_offsets.map do |offset|
59
- TrueTypeFont.from_ttc(io, offset)
59
+ TrueTypeFont.from_collection(io, offset)
60
60
  end
61
61
  end
62
62
 
63
63
  # List all fonts in the collection with basic metadata
64
64
  #
65
- # Overrides BaseCollection to use TrueType-specific from_ttc method.
65
+ # Uses the base class from_collection method.
66
66
  #
67
67
  # @param io [IO] Open file handle to read fonts from
68
68
  # @return [CollectionListInfo] List of fonts with metadata
@@ -73,7 +73,7 @@ module Fontisan
73
73
  require_relative "tables/name"
74
74
 
75
75
  fonts = font_offsets.map.with_index do |offset, index|
76
- font = TrueTypeFont.from_ttc(io, offset)
76
+ font = TrueTypeFont.from_collection(io, offset)
77
77
 
78
78
  # Extract basic font info
79
79
  name_table = font.table("name")
@@ -119,7 +119,7 @@ module Fontisan
119
119
 
120
120
  # Calculate table sharing statistics
121
121
  #
122
- # Overrides BaseCollection to use TrueType-specific from_ttc method.
122
+ # Uses the base class from_collection method.
123
123
  #
124
124
  # @param io [IO] Open file handle
125
125
  # @return [TableSharingInfo] Sharing statistics
@@ -129,7 +129,7 @@ module Fontisan
129
129
 
130
130
  # Extract all fonts
131
131
  fonts = font_offsets.map do |offset|
132
- TrueTypeFont.from_ttc(io, offset)
132
+ TrueTypeFont.from_collection(io, offset)
133
133
  end
134
134
 
135
135
  # Build table hash map (checksum -> size)
@@ -23,66 +23,8 @@ module Fontisan
23
23
  # ttf.to_file("output.ttf")
24
24
  #
25
25
  # @example Reading from TTC collection
26
- # ttf = TrueTypeFont.from_ttc(io, offset)
26
+ # ttf = TrueTypeFont.from_collection(io, offset)
27
27
  class TrueTypeFont < SfntFont
28
- # Read TrueType Font from a file
29
- #
30
- # @param path [String] Path to the TTF file
31
- # @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
32
- # @param lazy [Boolean] If true, load tables on demand (default: false)
33
- # @return [TrueTypeFont] A new instance
34
- # @raise [ArgumentError] if path is nil or empty, or if mode is invalid
35
- # @raise [Errno::ENOENT] if file does not exist
36
- # @raise [RuntimeError] if file format is invalid
37
- def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
38
- if path.nil? || path.to_s.empty?
39
- raise ArgumentError,
40
- "path cannot be nil or empty"
41
- end
42
- raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
43
-
44
- # Validate mode
45
- LoadingModes.validate_mode!(mode)
46
-
47
- File.open(path, "rb") do |io|
48
- font = read(io)
49
- font.initialize_storage
50
- font.loading_mode = mode
51
- font.lazy_load_enabled = lazy
52
-
53
- if lazy
54
- # Reuse existing IO handle by duplicating it to prevent double file open
55
- # The dup ensures the handle stays open after this block closes
56
- font.io_source = io.dup
57
- font.setup_finalizer
58
- else
59
- # Read tables upfront
60
- font.read_table_data(io)
61
- end
62
-
63
- font
64
- end
65
- rescue BinData::ValidityError, EOFError => e
66
- raise "Invalid TTF file: #{e.message}"
67
- end
68
-
69
- # Read TrueType Font from TTC at specific offset
70
- #
71
- # @param io [IO] Open file handle
72
- # @param offset [Integer] Byte offset to the font
73
- # @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
74
- # @return [TrueTypeFont] A new instance
75
- def self.from_ttc(io, offset, mode: LoadingModes::FULL)
76
- LoadingModes.validate_mode!(mode)
77
-
78
- io.seek(offset)
79
- font = read(io)
80
- font.initialize_storage
81
- font.loading_mode = mode
82
- font.read_table_data(io)
83
- font
84
- end
85
-
86
28
  # Check if font is TrueType flavored
87
29
  #
88
30
  # @return [Boolean] true for TrueType fonts
@@ -153,7 +153,8 @@ module Fontisan
153
153
  elsif @copyright.nil? && (match = line.match(/^Notice\s+(\S.*)/i))
154
154
  @copyright = match[1].strip
155
155
  elsif @font_bbox.nil? && (match = line.match(/^FontBBox\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$/i))
156
- @font_bbox = [match[1].to_i, match[2].to_i, match[3].to_i, match[4].to_i]
156
+ @font_bbox = [match[1].to_i, match[2].to_i, match[3].to_i,
157
+ match[4].to_i]
157
158
  end
158
159
 
159
160
  # Break early if all metrics found