fontisan 0.4.23 → 0.4.24

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +240 -29
  3. data/Gemfile +6 -0
  4. data/Rakefile +9 -6
  5. data/benchmark/compile_benchmark.rb +13 -5
  6. data/docs/.vitepress/config.ts +1 -0
  7. data/docs/STITCHER_GUIDE.adoc +47 -3
  8. data/docs/api/layer.md +89 -0
  9. data/docs/cli/subset.md +25 -6
  10. data/docs/guide/cli/subset.md +31 -0
  11. data/docs/guide/color-fonts/bitmaps.md +17 -0
  12. data/lib/fontisan/cli.rb +2 -1
  13. data/lib/fontisan/collection/writer.rb +2 -1
  14. data/lib/fontisan/commands/validate_collection_command.rb +7 -1
  15. data/lib/fontisan/commands.rb +2 -1
  16. data/lib/fontisan/converters/collection_converter.rb +6 -1
  17. data/lib/fontisan/converters/svg_generator.rb +3 -1
  18. data/lib/fontisan/stitcher/collection_result.rb +2 -1
  19. data/lib/fontisan/stitcher/glyph_copier.rb +2 -1
  20. data/lib/fontisan/stitcher/partition_strategy/by_block.rb +3 -1
  21. data/lib/fontisan/stitcher/partition_strategy/by_script.rb +6 -2
  22. data/lib/fontisan/stitcher/source.rb +2 -1
  23. data/lib/fontisan/stitcher.rb +2 -1
  24. data/lib/fontisan/subset/table_strategy/glyf_loca_builder.rb +2 -1
  25. data/lib/fontisan/svg/standalone_glyph.rb +4 -1
  26. data/lib/fontisan/svg_to_glyf/assembler.rb +6 -3
  27. data/lib/fontisan/svg_to_glyf/geometry/transform_parser.rb +11 -4
  28. data/lib/fontisan/svg_to_glyf/geometry.rb +4 -2
  29. data/lib/fontisan/tables/cff/cff2_charstring_builder.rb +11 -5
  30. data/lib/fontisan/tables/cff.rb +2 -1
  31. data/lib/fontisan/tables/cff2/index_builder.rb +2 -1
  32. data/lib/fontisan/tables.rb +2 -1
  33. data/lib/fontisan/ufo/cli.rb +4 -1
  34. data/lib/fontisan/ufo/compile/cbdt_cblc.rb +2 -1
  35. data/lib/fontisan/ufo/compile/cff.rb +6 -2
  36. data/lib/fontisan/ufo/compile/cmap.rb +11 -5
  37. data/lib/fontisan/ufo/compile/cpal.rb +2 -1
  38. data/lib/fontisan/ufo/compile/feature_writers/gdef.rb +3 -1
  39. data/lib/fontisan/ufo/compile/feature_writers/mark_family_base.rb +3 -1
  40. data/lib/fontisan/ufo/compile/feature_writers.rb +2 -1
  41. data/lib/fontisan/ufo/compile/filters/cubic_to_quadratic.rb +4 -2
  42. data/lib/fontisan/ufo/compile/filters/remove_overlaps.rb +2 -1
  43. data/lib/fontisan/ufo/compile/fvar.rb +7 -3
  44. data/lib/fontisan/ufo/compile/glyf_loca.rb +4 -2
  45. data/lib/fontisan/ufo/compile/gvar.rb +5 -2
  46. data/lib/fontisan/ufo/compile/head.rb +2 -1
  47. data/lib/fontisan/ufo/compile/item_variation_store.rb +2 -1
  48. data/lib/fontisan/ufo/compile/name.rb +3 -1
  49. data/lib/fontisan/ufo/compile/sbix.rb +2 -1
  50. data/lib/fontisan/ufo/compile/stat.rb +6 -3
  51. data/lib/fontisan/ufo/convert/from_bin_data.rb +6 -2
  52. data/lib/fontisan/ufo/convert/to_dfont.rb +6 -2
  53. data/lib/fontisan/ufo/convert/to_otc.rb +4 -1
  54. data/lib/fontisan/ufo/convert/to_postscript.rb +8 -3
  55. data/lib/fontisan/ufo/convert/to_woff.rb +8 -3
  56. data/lib/fontisan/ufo/convert/to_woff2.rb +8 -3
  57. data/lib/fontisan/ufo/convert.rb +4 -1
  58. data/lib/fontisan/ufo/info.rb +4 -2
  59. data/lib/fontisan/ufo/plist.rb +7 -2
  60. data/lib/fontisan/ufo/reader.rb +3 -1
  61. data/lib/fontisan/ufo/writer.rb +13 -5
  62. data/lib/fontisan/version.rb +1 -1
  63. data/lib/fontisan/woff2/collection_decoder.rb +4 -1
  64. data/lib/fontisan/woff2/collection_encoder.rb +4 -1
  65. data/lib/fontisan/woff2/glyf_canonicalizer.rb +2 -1
  66. data/lib/fontisan/woff2/glyf_loca_reconstruct.rb +5 -2
  67. data/lib/fontisan/woff2/sfnt_checksum.rb +2 -1
  68. data/lib/fontisan.rb +0 -1
  69. metadata +2 -3
  70. data/lib/fontisan/tasks/fixture_downloader.rb +0 -162
  71. data/lib/fontisan/tasks.rb +0 -11
@@ -78,7 +78,9 @@ module Fontisan
78
78
  def heuristic_class(glyph)
79
79
  anchor_names = glyph.anchors.map(&:name)
80
80
  mark_anchor_pattern = /\A_[a-zA-Z]+\z/
81
- return 3 if anchor_names.any? { |n| mark_anchor_pattern.match?(n.to_s) }
81
+ return 3 if anchor_names.any? do |n|
82
+ mark_anchor_pattern.match?(n.to_s)
83
+ end
82
84
  return 2 if glyph.name.to_s.end_with?(".liga")
83
85
 
84
86
  nil
@@ -28,7 +28,9 @@ module Fontisan
28
28
 
29
29
  attachments[class_name] ||= new_class_entry
30
30
  attachments[class_name][:marks][mark_name] = mark_anchor
31
- bases.each { |n, a| attachments[class_name][base_bucket_key][n] = a }
31
+ bases.each do |n, a|
32
+ attachments[class_name][base_bucket_key][n] = a
33
+ end
32
34
  end
33
35
  end
34
36
 
@@ -16,7 +16,8 @@ module Fontisan
16
16
  # entry. No edits to the compiler.
17
17
  module FeatureWriters
18
18
  autoload :Base, "fontisan/ufo/compile/feature_writers/base"
19
- autoload :MarkFamilyBase, "fontisan/ufo/compile/feature_writers/mark_family_base"
19
+ autoload :MarkFamilyBase,
20
+ "fontisan/ufo/compile/feature_writers/mark_family_base"
20
21
  autoload :Kern, "fontisan/ufo/compile/feature_writers/kern"
21
22
  autoload :Kern2, "fontisan/ufo/compile/feature_writers/kern2"
22
23
  autoload :Gdef, "fontisan/ufo/compile/feature_writers/gdef"
@@ -134,8 +134,10 @@ module Fontisan
134
134
  right_c2 = Point.new(x: r2x, y: r2y, type: "offcurve")
135
135
  right_p3 = p3
136
136
 
137
- left = subdivide_cubic(left_p0, left_c1, left_c2, left_p3, tolerance)
138
- right = subdivide_cubic(right_p0, right_c1, right_c2, right_p3, tolerance)
137
+ left = subdivide_cubic(left_p0, left_c1, left_c2, left_p3,
138
+ tolerance)
139
+ right = subdivide_cubic(right_p0, right_c1, right_c2, right_p3,
140
+ tolerance)
139
141
 
140
142
  # Drop the duplicated midpoint point between halves
141
143
  left + right
@@ -56,7 +56,8 @@ module Fontisan
56
56
  next if i == j || drop.include?(j)
57
57
 
58
58
  # Drop inner when its bbox is fully inside outer's.
59
- if contained_in?(bboxes[j], bboxes[i]) && (inner.points.size <= outer.points.size)
59
+ if contained_in?(bboxes[j],
60
+ bboxes[i]) && (inner.points.size <= outer.points.size)
60
61
  # Sanity: only drop if the point count is smaller —
61
62
  # a fully-contained contour with MORE points is
62
63
  # almost certainly the outer one in a malformed
@@ -28,7 +28,8 @@ module Fontisan
28
28
 
29
29
  axes_bytes = build_axes(axes)
30
30
  instances_bytes = build_instances(instances || [], axes.size)
31
- header = build_header(axes.size, axes_bytes, instances_bytes, instances)
31
+ header = build_header(axes.size, axes_bytes, instances_bytes,
32
+ instances)
32
33
  header + axes_bytes + instances_bytes
33
34
  end
34
35
 
@@ -38,7 +39,8 @@ module Fontisan
38
39
  # majorVersion (2) + minorVersion (2) + axesArrayOffset (2)
39
40
  # + reserved (2) + axisCount (2) + axisSize (2)
40
41
  # + instanceCount (2) + instanceSize (2)
41
- def self.build_header(axis_count, axes_bytes, _instances_bytes, instances)
42
+ def self.build_header(axis_count, axes_bytes, _instances_bytes,
43
+ instances)
42
44
  axes_offset = 16
43
45
  axes_offset + axes_bytes.bytesize
44
46
 
@@ -86,7 +88,9 @@ module Fontisan
86
88
  name_id = inst[:name_id] || inst["name_id"] || 0
87
89
  flags = inst[:flags] || inst["flags"] || 0
88
90
  coords = inst[:coords] || inst["coords"] || []
89
- padded = coords.first(axis_count) + Array.new([axis_count - coords.size, 0].max, 0)
91
+ padded = coords.first(axis_count) + Array.new(
92
+ [axis_count - coords.size, 0].max, 0
93
+ )
90
94
  padded = padded.first(axis_count).map { |c| fixed_value(c) }
91
95
 
92
96
  io << [name_id, flags].pack("nn")
@@ -41,7 +41,8 @@ module Fontisan
41
41
  offsets.map { |o| o / 2 }.pack("n*")
42
42
  end
43
43
 
44
- { "glyf" => glyf_bytes, "loca" => loca_bytes, :loca_format => use_long ? 1 : 0 }
44
+ { "glyf" => glyf_bytes, "loca" => loca_bytes,
45
+ :loca_format => use_long ? 1 : 0 }
45
46
  end
46
47
 
47
48
  # Encode a single glyph into glyf bytes. Empty glyphs (no
@@ -138,7 +139,8 @@ module Fontisan
138
139
  # nothing).
139
140
  ""
140
141
  end
141
- private_class_method :encode_glyph, :encode_simple, :encode_points, :encode_composite
142
+ private_class_method :encode_glyph, :encode_simple, :encode_points,
143
+ :encode_composite
142
144
  end
143
145
  end
144
146
  end
@@ -121,7 +121,9 @@ module Fontisan
121
121
  deltas = tuple[:deltas]
122
122
 
123
123
  # Encode delta data
124
- all_fit_int8 = deltas.all? { |dx, dy| dx.between?(-127, 127) && dy.between?(-127, 127) }
124
+ all_fit_int8 = deltas.all? do |dx, dy|
125
+ dx.between?(-127, 127) && dy.between?(-127, 127)
126
+ end
125
127
 
126
128
  point_count = deltas.size
127
129
  flags = point_count & POINT_COUNT_MASK
@@ -195,7 +197,8 @@ module Fontisan
195
197
 
196
198
  def self.build_empty(glyph_count)
197
199
  # Minimal gvar with no variation data
198
- header = [VERSION_MAJOR, VERSION_MINOR, 0, 0, 0, glyph_count, 1, glyph_count + 16].pack("nnnnnnNN")
200
+ header = [VERSION_MAJOR, VERSION_MINOR, 0, 0, 0, glyph_count, 1,
201
+ glyph_count + 16].pack("nnnnnnNN")
199
202
  offsets = Array.new(glyph_count + 1, 0).pack("C*")
200
203
  header + offsets
201
204
  end
@@ -19,7 +19,8 @@ module Fontisan
19
19
  # @param glyphs [Array<Fontisan::Ufo::Glyph>] (unused here;
20
20
  # bbox is computed by the caller for performance)
21
21
  # @return [Fontisan::Tables::Head]
22
- def self.build(font, glyphs:, units_per_em: nil, loca_format: LOCA_FORMAT_LONG)
22
+ def self.build(font, glyphs:, units_per_em: nil,
23
+ loca_format: LOCA_FORMAT_LONG)
23
24
  bbox = font_bbox(font, glyphs)
24
25
  Fontisan::Tables::Head.new(
25
26
  version_raw: 0x00010000,
@@ -62,7 +62,8 @@ module Fontisan
62
62
  io << [regions.size].pack("n") # regionCount
63
63
  regions.each do |region|
64
64
  region.each do |coords|
65
- io << [f2dot14(coords[:start]), f2dot14(coords[:peak]), f2dot14(coords[:end])].pack("nnn")
65
+ io << [f2dot14(coords[:start]), f2dot14(coords[:peak]),
66
+ f2dot14(coords[:end])].pack("nnn")
66
67
  end
67
68
  end
68
69
  io
@@ -51,7 +51,9 @@ module Fontisan
51
51
 
52
52
  def self.format0_bytes(records)
53
53
  # Strings are stored UTF-16BE on disk (Windows Unicode).
54
- encoded = records.map { |r| r[:value].encode("UTF-16BE").force_encoding("BINARY") }
54
+ encoded = records.map do |r|
55
+ r[:value].encode("UTF-16BE").force_encoding("BINARY")
56
+ end
55
57
  storage = encoded.join
56
58
  storage_offset = 6 + (records.size * 12)
57
59
 
@@ -75,7 +75,8 @@ module Fontisan
75
75
  if glyph && glyph[:data]
76
76
  offsets << current_offset
77
77
  data = glyph[:data].b
78
- glyph_data << [glyph[:origin_x] || 0, glyph[:origin_y] || 0].pack("nn")
78
+ glyph_data << [glyph[:origin_x] || 0,
79
+ glyph[:origin_y] || 0].pack("nn")
79
80
  glyph_data << (glyph[:graphic_type] || PNG_TYPE).ljust(4)[0, 4]
80
81
  glyph_data << data
81
82
  current_offset += 8 + data.bytesize
@@ -26,7 +26,8 @@ module Fontisan
26
26
  axis_value_count = axis_value_list.size
27
27
 
28
28
  design_axes = serialize_design_axes(axes)
29
- value_tables, value_offsets = serialize_axis_values(axis_value_list, design_axes.bytesize)
29
+ value_tables, value_offsets = serialize_axis_values(axis_value_list,
30
+ design_axes.bytesize)
30
31
 
31
32
  header = serialize_header(
32
33
  design_axis_count: design_axis_count,
@@ -45,7 +46,8 @@ module Fontisan
45
46
  io
46
47
  end
47
48
 
48
- def self.serialize_header(design_axis_count:, design_axes_size:, axis_value_count:, elided_name_id:)
49
+ def self.serialize_header(design_axis_count:, design_axes_size:,
50
+ axis_value_count:, elided_name_id:)
49
51
  design_axes_offset = HEADER_SIZE
50
52
  offset_to_axis_value_offsets = design_axes_offset + design_axes_size
51
53
 
@@ -86,7 +88,8 @@ module Fontisan
86
88
  flags = av[:flags] || av["flags"] || 0
87
89
  name_id = av[:name_id] || av["name_id"] || 0
88
90
  value = f2dot14(av[:value] || av["value"] || 0)
89
- value_tables << [format, axis_idx, flags, name_id, value].pack("nnnnn")
91
+ value_tables << [format, axis_idx, flags, name_id,
92
+ value].pack("nnnnn")
90
93
  end
91
94
 
92
95
  [value_tables, value_offsets]
@@ -82,7 +82,8 @@ module Fontisan
82
82
 
83
83
  if raw && raw.encoding == Encoding::UTF_16BE
84
84
  raw.encode("UTF-8")
85
- elsif raw && raw.bytesize >= 2 && raw.getbyte(0).between?(0, 127) && raw.getbyte(1).zero?
85
+ elsif raw && raw.bytesize >= 2 && raw.getbyte(0).between?(0,
86
+ 127) && raw.getbyte(1).zero?
86
87
  # Looks like UTF-16BE
87
88
  raw.force_encoding("UTF-16BE").encode("UTF-8")
88
89
  else
@@ -165,7 +166,10 @@ module Fontisan
165
166
  return unless glyf && loca && head
166
167
 
167
168
  # Tables need context-aware initialization before per-glyph access.
168
- loca.parse_with_context(head.index_to_loc_format, num_glyphs) if loca.respond_to?(:parse_with_context)
169
+ if loca.respond_to?(:parse_with_context)
170
+ loca.parse_with_context(head.index_to_loc_format,
171
+ num_glyphs)
172
+ end
169
173
 
170
174
  num_glyphs.times do |gid|
171
175
  glyph_name = glyph_name_for(font, gid) || "glyph#{gid}"
@@ -17,10 +17,14 @@ module Fontisan
17
17
  # @return [String] the output_path
18
18
  def self.convert(ufo, output_path:, compiler: :ttf, **_opts)
19
19
  compiler_class = Convert::COMPILER_FOR_FORMAT[compiler.to_sym]
20
- raise ArgumentError, "unknown intermediate compiler: #{compiler.inspect}" unless compiler_class
20
+ unless compiler_class
21
+ raise ArgumentError,
22
+ "unknown intermediate compiler: #{compiler.inspect}"
23
+ end
21
24
 
22
25
  Dir.mktmpdir do |dir|
23
- intermediate_path = File.join(dir, "intermediate#{ext_for(compiler)}")
26
+ intermediate_path = File.join(dir,
27
+ "intermediate#{ext_for(compiler)}")
24
28
  compiler_class.new(ufo).compile(output_path: intermediate_path)
25
29
 
26
30
  loaded = Fontisan::FontLoader.load(intermediate_path)
@@ -18,7 +18,10 @@ module Fontisan
18
18
  # @return [String] the output_path
19
19
  def self.convert(ufo, output_path:, compiler: :otf, **_opts)
20
20
  compiler_class = Convert::COMPILER_FOR_FORMAT[compiler.to_sym]
21
- raise ArgumentError, "unknown intermediate compiler: #{compiler.inspect}" unless compiler_class
21
+ unless compiler_class
22
+ raise ArgumentError,
23
+ "unknown intermediate compiler: #{compiler.inspect}"
24
+ end
22
25
 
23
26
  Dir.mktmpdir do |dir|
24
27
  intermediate_path = File.join(dir, "intermediate.otf")
@@ -17,12 +17,17 @@ module Fontisan
17
17
  # @param ps_options [Hash] forwarded to the generator
18
18
  # (encoding, upm_scale, convert_curves)
19
19
  # @return [String] the output_path
20
- def self.convert(ufo, output_path:, generator_class:, compiler: :ttf, **ps_options)
20
+ def self.convert(ufo, output_path:, generator_class:, compiler: :ttf,
21
+ **ps_options)
21
22
  compiler_class = Convert::COMPILER_FOR_FORMAT[compiler.to_sym]
22
- raise ArgumentError, "unknown intermediate compiler: #{compiler.inspect}" unless compiler_class
23
+ unless compiler_class
24
+ raise ArgumentError,
25
+ "unknown intermediate compiler: #{compiler.inspect}"
26
+ end
23
27
 
24
28
  Dir.mktmpdir do |dir|
25
- intermediate_path = File.join(dir, "intermediate#{ext_for(compiler)}")
29
+ intermediate_path = File.join(dir,
30
+ "intermediate#{ext_for(compiler)}")
26
31
  compiler_class.new(ufo).compile(output_path: intermediate_path)
27
32
 
28
33
  loaded = Fontisan::FontLoader.load(intermediate_path)
@@ -32,14 +32,19 @@ module Fontisan
32
32
  # @return [String] the output_path
33
33
  def self.convert(ufo, output_path:, compiler: :ttf, **woff_options)
34
34
  compiler_class = Convert::COMPILER_FOR_FORMAT[compiler.to_sym]
35
- raise ArgumentError, "unknown intermediate compiler: #{compiler.inspect}" unless compiler_class
35
+ unless compiler_class
36
+ raise ArgumentError,
37
+ "unknown intermediate compiler: #{compiler.inspect}"
38
+ end
36
39
 
37
40
  Dir.mktmpdir do |dir|
38
- intermediate_path = File.join(dir, "intermediate#{format_ext(compiler)}")
41
+ intermediate_path = File.join(dir,
42
+ "intermediate#{format_ext(compiler)}")
39
43
  compiler_class.new(ufo).compile(output_path: intermediate_path)
40
44
 
41
45
  loaded = Fontisan::FontLoader.load(intermediate_path)
42
- woff_bytes = Fontisan::Converters::WoffWriter.new.convert(loaded, woff_options)
46
+ woff_bytes = Fontisan::Converters::WoffWriter.new.convert(loaded,
47
+ woff_options)
43
48
  File.binwrite(output_path, woff_bytes)
44
49
  end
45
50
 
@@ -21,14 +21,19 @@ module Fontisan
21
21
  # @return [String] the output_path
22
22
  def self.convert(ufo, output_path:, compiler: :ttf, **woff2_options)
23
23
  compiler_class = Convert::COMPILER_FOR_FORMAT[compiler.to_sym]
24
- raise ArgumentError, "unknown intermediate compiler: #{compiler.inspect}" unless compiler_class
24
+ unless compiler_class
25
+ raise ArgumentError,
26
+ "unknown intermediate compiler: #{compiler.inspect}"
27
+ end
25
28
 
26
29
  Dir.mktmpdir do |dir|
27
- intermediate_path = File.join(dir, "intermediate#{format_ext(compiler)}")
30
+ intermediate_path = File.join(dir,
31
+ "intermediate#{format_ext(compiler)}")
28
32
  compiler_class.new(ufo).compile(output_path: intermediate_path)
29
33
 
30
34
  loaded = Fontisan::FontLoader.load(intermediate_path)
31
- result = Fontisan::Converters::Woff2Encoder.new.convert(loaded, woff2_options)
35
+ result = Fontisan::Converters::Woff2Encoder.new.convert(loaded,
36
+ woff2_options)
32
37
  File.binwrite(output_path, result[:woff2_binary])
33
38
  end
34
39
 
@@ -71,7 +71,10 @@ module Fontisan
71
71
  end
72
72
 
73
73
  compiler = COMPILER_FOR_FORMAT[format_key]
74
- raise ArgumentError, "unknown UFO output format: #{to.inspect}" unless compiler
74
+ unless compiler
75
+ raise ArgumentError,
76
+ "unknown UFO output format: #{to.inspect}"
77
+ end
75
78
 
76
79
  compiler.new(ufo).compile(output_path: output_path)
77
80
  output_path
@@ -81,8 +81,10 @@ module Fontisan
81
81
  # @return [Array(Integer, Integer)] [major, minor]
82
82
  def self.parse_version(version)
83
83
  case version.to_s
84
- when /\A(\d+)\.(\d+)\.\d+\z/ then [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i]
85
- when /\A(\d+)\.(\d+)\z/ then [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i]
84
+ when /\A(\d+)\.(\d+)\.\d+\z/ then [Regexp.last_match(1).to_i,
85
+ Regexp.last_match(2).to_i]
86
+ when /\A(\d+)\.(\d+)\z/ then [Regexp.last_match(1).to_i,
87
+ Regexp.last_match(2).to_i]
86
88
  when /\A(\d+)\z/ then [Regexp.last_match(1).to_i, 0]
87
89
  else [0, 0]
88
90
  end
@@ -25,7 +25,9 @@ module Fontisan
25
25
  root = doc.root
26
26
  raise ParseError, "no <plist> root element" unless root&.name == "plist"
27
27
 
28
- parse_value(root.children.find { |c| c.element? || c.cdata? || c.text? && !c.text.strip.empty? })
28
+ parse_value(root.children.find do |c|
29
+ c.element? || c.cdata? || c.text? && !c.text.strip.empty?
30
+ end)
29
31
  end
30
32
 
31
33
  # @param value [Object] the value to serialize
@@ -73,7 +75,10 @@ module Fontisan
73
75
  # dict children are key/value pairs (key first, then value)
74
76
  while children.any?
75
77
  key_node = children.shift
76
- raise ParseError, "dict key is not <key>" unless key_node.name == "key"
78
+ unless key_node.name == "key"
79
+ raise ParseError,
80
+ "dict key is not <key>"
81
+ end
77
82
 
78
83
  value_node = children.shift
79
84
  result[key_node.text] = parse_value(value_node)
@@ -94,7 +94,9 @@ module Fontisan
94
94
  if order.first.is_a?(Hash)
95
95
  order.reduce({}) { |h, pair| h.merge(pair) }
96
96
  else
97
- order.to_h { |filename| [File.basename(filename, ".glif"), filename] }
97
+ order.to_h do |filename|
98
+ [File.basename(filename, ".glif"), filename]
99
+ end
98
100
  end
99
101
  else
100
102
  raise "unsupported contents.plist format: #{order.class}"
@@ -50,7 +50,8 @@ module Fontisan
50
50
  end
51
51
 
52
52
  def write_fontinfo(path)
53
- File.write(File.join(path, "fontinfo.plist"), Plist.emit(@font.info.to_plist))
53
+ File.write(File.join(path, "fontinfo.plist"),
54
+ Plist.emit(@font.info.to_plist))
54
55
  end
55
56
 
56
57
  def write_layercontents(path)
@@ -75,11 +76,17 @@ module Fontisan
75
76
  FileUtils.mkpath(layer_dir)
76
77
 
77
78
  contents =
78
- layer.glyphs.transform_values { |g| "#{safe_filename(g.name)}.glif" }
79
- File.write(File.join(layer_dir, "contents.plist"), Plist.emit(contents))
79
+ layer.glyphs.transform_values do |g|
80
+ "#{safe_filename(g.name)}.glif"
81
+ end
82
+ File.write(File.join(layer_dir, "contents.plist"),
83
+ Plist.emit(contents))
80
84
 
81
85
  layer.glyphs.each_value do |glyph|
82
- File.write(File.join(layer_dir, "#{safe_filename(glyph.name)}.glif"), glyph.to_glif)
86
+ File.write(
87
+ File.join(layer_dir,
88
+ "#{safe_filename(glyph.name)}.glif"), glyph.to_glif
89
+ )
83
90
  end
84
91
  end
85
92
  end
@@ -96,7 +103,8 @@ module Fontisan
96
103
  def write_kerning(path)
97
104
  return if @font.kerning.empty?
98
105
 
99
- File.write(File.join(path, "kerning.plist"), Plist.emit(@font.kerning.to_plist))
106
+ File.write(File.join(path, "kerning.plist"),
107
+ Plist.emit(@font.kerning.to_plist))
100
108
  end
101
109
 
102
110
  def write_features(path)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fontisan
4
- VERSION = "0.4.23"
4
+ VERSION = "0.4.24"
5
5
  end
@@ -131,7 +131,10 @@ module Fontisan
131
131
  def read_collection_directory(pos)
132
132
  version = @data[pos, 4].unpack1("N")
133
133
  pos += 4
134
- raise InvalidFontError, "Unsupported CollectionHeader version 0x#{version.to_s(16)}" unless version == 0x00010000
134
+ unless version == 0x00010000
135
+ raise InvalidFontError,
136
+ "Unsupported CollectionHeader version 0x#{version.to_s(16)}"
137
+ end
135
138
 
136
139
  num_fonts, pos = UInt255.decode_at(@data, pos)
137
140
  font_entries = Array.new(num_fonts) do
@@ -32,7 +32,10 @@ module Fontisan
32
32
  # @param fonts [Array<TrueTypeFont, OpenTypeFont>] Source fonts
33
33
  # @return [String] WOFF2 collection binary
34
34
  def encode_fonts(fonts)
35
- raise ArgumentError, "fonts cannot be empty" if fonts.nil? || fonts.empty?
35
+ if fonts.nil? || fonts.empty?
36
+ raise ArgumentError,
37
+ "fonts cannot be empty"
38
+ end
36
39
 
37
40
  prepared = fonts.map.with_index { |font, i| prepare_font(font, i) }
38
41
  _, font_to_ckeys = deduplicate(prepared)
@@ -50,7 +50,8 @@ module Fontisan
50
50
  start_offset = source_offsets[i]
51
51
  end_offset = source_offsets[i + 1]
52
52
  if start_offset < end_offset
53
- glyf << @glyf_data.byteslice(start_offset, end_offset - start_offset)
53
+ glyf << @glyf_data.byteslice(start_offset,
54
+ end_offset - start_offset)
54
55
  end
55
56
  remainder = glyf.bytesize % 4
56
57
  glyf << ("\x00" * (4 - remainder)) if remainder.positive?
@@ -131,7 +131,8 @@ module Fontisan
131
131
  streams[:bbox_entries] = StringIO.new(bbox_blob[bitmap_size..] || "")
132
132
 
133
133
  # overlapSimpleBitmap follows all streams when optionFlags bit 0 set.
134
- streams[:overlap_bitmap] = header[:has_overlap_bitmap] ? @data[pos, overlap_size] : ""
134
+ streams[:overlap_bitmap] =
135
+ header[:has_overlap_bitmap] ? @data[pos, overlap_size] : ""
135
136
 
136
137
  # nContour is read positionally (int16 per glyph).
137
138
  nc_data = streams[:n_contour].string
@@ -178,7 +179,9 @@ module Fontisan
178
179
  x = 0
179
180
  y = 0
180
181
  triplet_flags.each do |flag|
181
- dx, dy, oc = TripletCodec.decode(flag, read_triplet_payload(flag, streams[:glyph]))
182
+ dx, dy, oc = TripletCodec.decode(flag,
183
+ read_triplet_payload(flag,
184
+ streams[:glyph]))
182
185
  x += dx
183
186
  y += dy
184
187
  xs << x
@@ -97,7 +97,8 @@ module Fontisan
97
97
  def per_table_checksum(table)
98
98
  data = table.bytes
99
99
  if table.tag == "head"
100
- data = "#{data.byteslice(0, 8)}#{['00000000'].pack('H8')}#{data.byteslice(12..)}"
100
+ data = "#{data.byteslice(0,
101
+ 8)}#{['00000000'].pack('H8')}#{data.byteslice(12..)}"
101
102
  end
102
103
  Utilities::ChecksumCalculator.calculate_table_checksum(data)
103
104
  end
data/lib/fontisan.rb CHANGED
@@ -119,7 +119,6 @@ module Fontisan
119
119
  autoload :SfntBuilder, "fontisan/sfnt_builder"
120
120
  autoload :Stitcher, "fontisan/stitcher"
121
121
  autoload :StitcherCli, "fontisan/stitcher_cli"
122
- autoload :Tasks, "fontisan/tasks"
123
122
  autoload :TrueTypeCollection, "fontisan/true_type_collection"
124
123
  autoload :TrueTypeFont, "fontisan/true_type_font"
125
124
  autoload :TrueTypeFontExtensions, "fontisan/true_type_font_extensions"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontisan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.23
4
+ version: 0.4.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -168,6 +168,7 @@ files:
168
168
  - docs/api/font-loader.md
169
169
  - docs/api/font-writer.md
170
170
  - docs/api/index.md
171
+ - docs/api/layer.md
171
172
  - docs/api/models/glyph-accessor.md
172
173
  - docs/api/models/glyph.md
173
174
  - docs/api/models/table-analyzer.md
@@ -588,8 +589,6 @@ files:
588
589
  - lib/fontisan/tables/svg.rb
589
590
  - lib/fontisan/tables/variation_common.rb
590
591
  - lib/fontisan/tables/vvar.rb
591
- - lib/fontisan/tasks.rb
592
- - lib/fontisan/tasks/fixture_downloader.rb
593
592
  - lib/fontisan/true_type_collection.rb
594
593
  - lib/fontisan/true_type_font.rb
595
594
  - lib/fontisan/true_type_font_extensions.rb