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.
@@ -49,7 +49,7 @@ module Fontisan
49
49
  cntrmask: 20, # CFF: 20, Type 1: Not supported (skip)
50
50
 
51
51
  # End char
52
- endchar: 14, # CFF: 14, Type 1: 14
52
+ endchar: 14, # CFF: 14, Type 1: 14
53
53
 
54
54
  # Miscellaneous
55
55
  callsubr: 10, # CFF: 10, Type 1: 10
@@ -83,7 +83,7 @@ module Fontisan
83
83
  def convert(cff_charstring, private_dict: {})
84
84
  # Parse CFF CharString into operations
85
85
  parser = Tables::Cff::CharStringParser.new(cff_charstring,
86
- stem_count: private_dict[:stem_count]&.to_i || 0)
86
+ stem_count: private_dict[:stem_count].to_i)
87
87
  operations = parser.parse
88
88
 
89
89
  # Extract width from operations (CFF spec: odd stack before first move = width)
@@ -106,13 +106,14 @@ module Fontisan
106
106
 
107
107
  # Find first move operator
108
108
  first_move_idx = operations.index do |op|
109
- %i[rmoveto hmoveto vmoveto rcurveline rrcurveline vvcurveto hhcurveto].include?(op[:name])
109
+ %i[rmoveto hmoveto vmoveto rcurveline rrcurveline vvcurveto
110
+ hhcurveto].include?(op[:name])
110
111
  end
111
112
 
112
113
  return @default_width unless first_move_idx
113
114
 
114
115
  # Count operands before first move
115
- operand_count = operations[0...first_move_idx].sum(0) do |op|
116
+ operand_count = operations[0...first_move_idx].sum do |op|
116
117
  op[:operands]&.length || 0
117
118
  end
118
119
 
@@ -140,10 +141,10 @@ module Fontisan
140
141
 
141
142
  # Add hsbw (horizontal sidebearing and width) at start
142
143
  # This is the standard width operator for horizontal fonts
143
- result << encode_number(0) # left sidebearing (usually 0 for CFF)
144
+ result << encode_number(0) # left sidebearing (usually 0 for CFF)
144
145
  result << encode_number(glyph_width)
145
146
  result << ESCAPE_BYTE
146
- result << 34 # hsbw operator (two-byte: 12 34)
147
+ result << 34 # hsbw operator (two-byte: 12 34)
147
148
 
148
149
  x = 0
149
150
  y = 0
@@ -154,11 +155,12 @@ module Fontisan
154
155
  if width && operations.any?
155
156
  # Count operands before first move to determine if width was in stack
156
157
  first_move_idx = operations.index do |op|
157
- %i[rmoveto hmoveto vmoveto rcurveline rrcurveline vvcurveto hhcurveto].include?(op[:name])
158
+ %i[rmoveto hmoveto vmoveto rcurveline rrcurveline vvcurveto
159
+ hhcurveto].include?(op[:name])
158
160
  end
159
161
 
160
162
  if first_move_idx
161
- operand_count = operations[0...first_move_idx].sum(0) do |op|
163
+ operand_count = operations[0...first_move_idx].sum do |op|
162
164
  op[:operands]&.length || 0
163
165
  end
164
166
 
@@ -182,16 +184,17 @@ module Fontisan
182
184
  end
183
185
 
184
186
  if operands.length >= 2
185
- dx, dy = operands[0], operands[1]
187
+ dx = operands[0]
188
+ dy = operands[1]
186
189
  x += dx
187
190
  y += dy
188
191
  result << encode_number(dx)
189
192
  result << encode_number(dy)
190
- result << 21 # rmoveto
193
+ result << 21 # rmoveto
191
194
  elsif operands.length == 1
192
195
  # Only dy (hmoveto/vmoveto style)
193
196
  result << encode_number(operands.first)
194
- result << 4 # vmoveto (closest approximation)
197
+ result << 4 # vmoveto (closest approximation)
195
198
  end
196
199
  first_move = false
197
200
  when :hmoveto
@@ -205,14 +208,14 @@ module Fontisan
205
208
  dx = operands.first
206
209
  x += dx if dx
207
210
  result << encode_number(dx)
208
- result << 22 # hmoveto
211
+ result << 22 # hmoveto
209
212
  first_move = false
210
213
  when :vmoveto
211
214
  # vmoveto dy
212
215
  dy = op[:operands].first
213
216
  y += dy if dy
214
217
  result << encode_number(dy)
215
- result << 4 # vmoveto
218
+ result << 4 # vmoveto
216
219
  first_move = false
217
220
  when :rlineto
218
221
  # rlineto dx dy
@@ -221,29 +224,31 @@ module Fontisan
221
224
  y += dy
222
225
  result << encode_number(dx)
223
226
  result << encode_number(dy)
224
- result << 5 # rlineto
227
+ result << 5 # rlineto
225
228
  first_move = false
226
229
  when :hlineto
227
230
  # hlineto dx
228
231
  dx = op[:operands].first
229
232
  x += dx
230
233
  result << encode_number(dx)
231
- result << 6 # hlineto
234
+ result << 6 # hlineto
232
235
  first_move = false
233
236
  when :vlineto
234
237
  # vlineto dy
235
238
  dy = op[:operands].first
236
239
  y += dy
237
240
  result << encode_number(dy)
238
- result << 7 # vlineto
241
+ result << 7 # vlineto
239
242
  first_move = false
240
243
  when :rrcurveto
241
244
  # rrcurveto dx1 dy1 dx2 dy2 dx3 dy3
242
245
  dx1, dy1, dx2, dy2, dx3, dy3 = op[:operands]
243
246
  x += dx1 + dx2 + dx3
244
247
  y += dy1 + dy2 + dy3
245
- [dx1, dy1, dx2, dy2, dx3, dy3].each { |val| result << encode_number(val) }
246
- result << 8 # rrcurveto
248
+ [dx1, dy1, dx2, dy2, dx3, dy3].each do |val|
249
+ result << encode_number(val)
250
+ end
251
+ result << 8 # rrcurveto
247
252
  first_move = false
248
253
  when :hhcurveto, :hvcurveto, :vhcurveto
249
254
  # Flexible curve operators
@@ -293,7 +298,7 @@ module Fontisan
293
298
  [num + 139].pack("C")
294
299
  else
295
300
  # Use escape sequence (255) followed by 2-byte signed integer
296
- num += 32768 if num < 0
301
+ num += 32768 if num.negative?
297
302
  [255, num % 256, num >> 8].pack("C*")
298
303
  end
299
304
  end
@@ -176,18 +176,39 @@ module Fontisan
176
176
  # puts priv.to_type1_format
177
177
  def to_type1_format
178
178
  result = []
179
- result << array_to_type1(:BlueValues, @blue_values) unless @blue_values.empty?
180
- result << array_to_type1(:OtherBlues, @other_blues) unless @other_blues.empty?
181
- result << array_to_type1(:FamilyBlues, @family_blues) unless @family_blues.empty?
182
- result << array_to_type1(:FamilyOtherBlues, @family_other_blues) unless @family_other_blues.empty?
179
+ unless @blue_values.empty?
180
+ result << array_to_type1(:BlueValues,
181
+ @blue_values)
182
+ end
183
+ unless @other_blues.empty?
184
+ result << array_to_type1(:OtherBlues,
185
+ @other_blues)
186
+ end
187
+ unless @family_blues.empty?
188
+ result << array_to_type1(:FamilyBlues,
189
+ @family_blues)
190
+ end
191
+ unless @family_other_blues.empty?
192
+ result << array_to_type1(:FamilyOtherBlues,
193
+ @family_other_blues)
194
+ end
183
195
  result << scalar_to_type1(:BlueScale, @blue_scale)
184
196
  result << scalar_to_type1(:BlueShift, @blue_shift)
185
197
  result << scalar_to_type1(:BlueFuzz, @blue_fuzz)
186
198
  result << array_to_type1(:StdHW, @std_hw) unless @std_hw.empty?
187
199
  result << array_to_type1(:StdVW, @std_vw) unless @std_vw.empty?
188
- result << array_to_type1(:StemSnapH, @stem_snap_h) unless @stem_snap_h.empty?
189
- result << array_to_type1(:StemSnapV, @stem_snap_v) unless @stem_snap_v.empty?
190
- result << boolean_to_type1(:ForceBold, @force_bold) unless @force_bold == false
200
+ unless @stem_snap_h.empty?
201
+ result << array_to_type1(:StemSnapH,
202
+ @stem_snap_h)
203
+ end
204
+ unless @stem_snap_v.empty?
205
+ result << array_to_type1(:StemSnapV,
206
+ @stem_snap_v)
207
+ end
208
+ unless @force_bold == false
209
+ result << boolean_to_type1(:ForceBold,
210
+ @force_bold)
211
+ end
191
212
  result << scalar_to_type1(:lenIV, @len_iv)
192
213
 
193
214
  result.join("\n")
@@ -68,11 +68,13 @@ module Fontisan
68
68
  accent_glyph_name = @charstrings.encoding[components[:accent]]
69
69
 
70
70
  if base_glyph_name.nil?
71
- raise Fontisan::Error, "Base glyph for char code #{components[:base]} not found"
71
+ raise Fontisan::Error,
72
+ "Base glyph for char code #{components[:base]} not found"
72
73
  end
73
74
 
74
75
  if accent_glyph_name.nil?
75
- raise Fontisan::Error, "Accent glyph for char code #{components[:accent]} not found"
76
+ raise Fontisan::Error,
77
+ "Accent glyph for char code #{components[:accent]} not found"
76
78
  end
77
79
 
78
80
  # Get CharStrings for base and accent
@@ -80,11 +82,13 @@ module Fontisan
80
82
  accent_charstring = @charstrings[accent_glyph_name]
81
83
 
82
84
  if base_charstring.nil?
83
- raise Fontisan::Error, "CharString not found for base glyph #{base_glyph_name}"
85
+ raise Fontisan::Error,
86
+ "CharString not found for base glyph #{base_glyph_name}"
84
87
  end
85
88
 
86
89
  if accent_charstring.nil?
87
- raise Fontisan::Error, "CharString not found for accent glyph #{accent_glyph_name}"
90
+ raise Fontisan::Error,
91
+ "CharString not found for accent glyph #{accent_glyph_name}"
88
92
  end
89
93
 
90
94
  # Parse both CharStrings into command sequences
@@ -92,7 +96,8 @@ module Fontisan
92
96
  accent_commands = parse_charstring_to_commands(accent_charstring)
93
97
 
94
98
  # Transform accent by (adx, ady) offset
95
- accent_commands = transform_commands(accent_commands, components[:adx], components[:ady])
99
+ accent_commands = transform_commands(accent_commands, components[:adx],
100
+ components[:ady])
96
101
 
97
102
  # Merge base and accent commands
98
103
  merged_commands = merge_outline_commands(base_commands, accent_commands)
@@ -278,8 +283,8 @@ module Fontisan
278
283
  dx1, dy1, dx2, dy2, dx3, dy3 = cmd[1..6]
279
284
  control_x = x + dx1
280
285
  control_y = y + dy1
281
- anchor_x = x + dx1 + dx2
282
- anchor_y = y + dy1 + dy2
286
+ x + dx1 + dx2
287
+ y + dy1 + dy2
283
288
  end_x = x + dx1 + dx2 + dx3
284
289
  end_y = y + dy1 + dy2 + dy3
285
290
 
@@ -288,7 +293,7 @@ module Fontisan
288
293
  cx: control_x,
289
294
  cy: control_y,
290
295
  x: end_x,
291
- y: end_y
296
+ y: end_y,
292
297
  }
293
298
  x = end_x
294
299
  y = end_y
@@ -326,13 +331,13 @@ module Fontisan
326
331
  # vhcurveto: dy1 dx2 dy2 dx3
327
332
  # hvcurveto: dx1 dy2 dx3 dy3
328
333
  if cmd[0] == :vhcurveto
329
- dy1, dx2, dy2, dx3 = cmd[1..4]
334
+ dy1, dx2, dy2, = cmd[1..4]
330
335
  control_x = x
331
336
  control_y = y + dy1
332
337
  end_x = x + dx2
333
338
  end_y = y + dy1 + dy2
334
339
  else
335
- dx1, dy2, dx3, dy3 = cmd[1..4]
340
+ dx1, dy2, _, dy3 = cmd[1..4]
336
341
  control_x = x + dx1
337
342
  control_y = y
338
343
  end_x = x + dx1 + dx2
@@ -344,7 +349,7 @@ module Fontisan
344
349
  cx: control_x,
345
350
  cy: control_y,
346
351
  x: end_x,
347
- y: end_y
352
+ y: end_y,
348
353
  }
349
354
  end
350
355
 
@@ -355,7 +360,7 @@ module Fontisan
355
360
  # @param dy [Integer] Y offset
356
361
  # @return [Array<Hash>] Transformed commands
357
362
  def transform_commands(commands, dx, dy)
358
- return commands if dx == 0 && dy == 0
363
+ return commands if dx.zero? && dy.zero?
359
364
 
360
365
  commands.map do |cmd|
361
366
  case cmd[:type]
@@ -367,7 +372,7 @@ module Fontisan
367
372
  cx: cmd[:cx] + dx,
368
373
  cy: cmd[:cy] + dy,
369
374
  x: cmd[:x] + dx,
370
- y: cmd[:y] + dy
375
+ y: cmd[:y] + dy,
371
376
  }
372
377
  when :curve_to
373
378
  {
@@ -377,7 +382,7 @@ module Fontisan
377
382
  cx2: cmd[:cx2] + dx,
378
383
  cy2: cmd[:cy2] + dy,
379
384
  x: cmd[:x] + dx,
380
- y: cmd[:y] + dy
385
+ y: cmd[:y] + dy,
381
386
  }
382
387
  else
383
388
  cmd # close_path, etc. pass through
@@ -428,8 +433,8 @@ module Fontisan
428
433
  # Use hsbw to set initial position
429
434
  dx = cmd[:x] - x
430
435
  # hsbw is a two-byte operator: 12 34
431
- charstring << encode_number(dx) # sbw value
432
- charstring << encode_number(0) # width (always 0 for decomposed glyphs)
436
+ charstring << encode_number(dx) # sbw value
437
+ charstring << encode_number(0) # width (always 0 for decomposed glyphs)
433
438
  charstring << 12 # First byte of two-byte operator
434
439
  charstring << 34 # Second byte - hsbw
435
440
  x = cmd[:x]
@@ -492,7 +497,7 @@ module Fontisan
492
497
  [num + 139].pack("C*")
493
498
  else
494
499
  # Use escape sequence (255) followed by 2-byte signed integer
495
- num += 32768 if num < 0
500
+ num += 32768 if num.negative?
496
501
  [255, num % 256, num >> 8].pack("C*")
497
502
  end
498
503
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fontisan
4
- VERSION = "0.2.13"
4
+ VERSION = "0.2.14"
5
5
  end
@@ -373,11 +373,11 @@ module Fontisan
373
373
  raise InvalidFontError,
374
374
  "Unknown WOFF2 flavor: 0x#{woff2.header.flavor.to_s(16)}"
375
375
  end
376
+ rescue BinData::ValidityError, EOFError => e
377
+ raise InvalidFontError, "Invalid WOFF2 file: #{e.message}"
376
378
  end
377
379
 
378
380
  woff2
379
- rescue BinData::ValidityError, EOFError => e
380
- raise InvalidFontError, "Invalid WOFF2 file: #{e.message}"
381
381
  end
382
382
 
383
383
  # Read table directory from IO
@@ -98,10 +98,10 @@ module Fontisan
98
98
  font.io_source = io
99
99
  font.read_compressed_table_data(io)
100
100
  font
101
+ rescue BinData::ValidityError, EOFError => e
102
+ Kernel.raise(::Fontisan::InvalidFontError,
103
+ "Invalid WOFF file: #{e.message}")
101
104
  end
102
- rescue BinData::ValidityError, EOFError => e
103
- Kernel.raise(::Fontisan::InvalidFontError,
104
- "Invalid WOFF file: #{e.message}")
105
105
  end
106
106
 
107
107
  # Initialize storage hashes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontisan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.13
4
+ version: 0.2.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-21 00:00:00.000000000 Z
11
+ date: 2026-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64