fontisan 0.4.15 → 0.4.16

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 422936ab5bbb785c6030c16efa61be31edd4c9e251828eabaa29e572a570bbb5
4
- data.tar.gz: ad05bb618741fb0958e1be540af840debb9ffa4d92be469930f8e11f6ccd63fb
3
+ metadata.gz: 1d27d25052549a912eab7392f8f0b34e7917fad9e9344d178b853bfe5a9fb476
4
+ data.tar.gz: 7fe03e99020f0a628efa4bac17236c455143345dbe4aef1dd1df5a8890cf00ad
5
5
  SHA512:
6
- metadata.gz: f9d938ed00f8bff70e0fe20b06751134faa1cb9c0f536467f1259866876d060f170ac94e0a89818a4f77662d873542c9a6bfb09d4da0de5577c3bda2a33f4efa
7
- data.tar.gz: e6d7679235dab59a1a26bf5948f0651d147b12fec4218c000626ff0291fbec33593cef8ba0466e189d63c20f6cdc0d6c53b88626f47178656a272248e8e12872
6
+ metadata.gz: 5ddb0c714d55d9f0e3b6b2ae02322f210d2392391d604368628cf6a789e2c1633645b08d4ee1edca6e05c0dc87e7c6e6ec550bc412bcc79fe751cc21f1e55f62
7
+ data.tar.gz: f8a646128fbadfd95df57bffc933a17095b3fb228603c941471198186df112bc517d836d09c567c1456b5aa8caed3aec4c14f8c561ba4cc19a4561bf75124940
@@ -227,6 +227,12 @@ module Fontisan
227
227
  # are kept in `table_data` so its `origLength` is preserved; the
228
228
  # transformed bytes are passed to the entries builder separately.
229
229
  #
230
+ # glyf.origLength is computed by round-tripping the transformed glyf
231
+ # through the decoder — this guarantees the directory matches what
232
+ # any compliant decoder will produce, including padding and minor
233
+ # re-encoding differences (OFF section 5.3.3 allows multiple valid
234
+ # reconstructions of the same glyph data).
235
+ #
230
236
  # @return [Hash{Symbol => Object}, nil]
231
237
  def apply_glyf_loca_transform!(table_data, font)
232
238
  return nil unless font.respond_to?(:has_table?)
@@ -240,17 +246,32 @@ module Fontisan
240
246
  head = font.table("head")
241
247
  return nil unless maxp && head
242
248
 
249
+ index_format = head.index_to_loc_format
250
+
243
251
  transformed = Woff2::GlyfLocaTransform.new(
244
252
  glyf_data:,
245
253
  loca_data:,
246
254
  num_glyphs: maxp.num_glyphs,
247
- index_format: head.index_to_loc_format,
255
+ index_format:,
248
256
  ).transform
249
257
 
250
- loca_orig_length = loca_data.bytesize
258
+ # Round-trip through the decoder to get the exact reconstructed
259
+ # sizes the directory must advertise. fontTools re-compiles glyf
260
+ # during encoding, producing sizes that differ from the source by
261
+ # small amounts (encoding variations per OFF section 5.3.3). Using
262
+ # the source bytesize causes fontTools' decoder to reject the
263
+ # WOFF2 with "not enough 'glyf' table data".
264
+ reconstructed = Woff2::GlyfLocaReconstruct.new(
265
+ transformed_glyf: transformed,
266
+ num_glyphs: maxp.num_glyphs,
267
+ index_format:,
268
+ ).reconstruct
269
+
270
+ glyf_orig_length = reconstructed[:glyf].bytesize
271
+ loca_orig_length = reconstructed[:loca].bytesize
251
272
  table_data.delete("loca")
252
273
 
253
- { transformed_glyf: transformed, loca_orig_length: }
274
+ { transformed_glyf: transformed, glyf_orig_length:, loca_orig_length: }
254
275
  end
255
276
 
256
277
  def get_table_data(font, tag)
@@ -277,7 +298,7 @@ module Fontisan
277
298
 
278
299
  table_data.keys.sort.each do |tag|
279
300
  if tag == "glyf" && glyf_transform
280
- entries << build_glyf_entry(table_data["glyf"],
301
+ entries << build_glyf_entry(glyf_transform[:glyf_orig_length],
281
302
  glyf_transform[:transformed_glyf])
282
303
  entries << build_loca_entry(glyf_transform[:loca_orig_length])
283
304
  transformed_data["glyf"] = glyf_transform[:transformed_glyf]
@@ -314,13 +335,13 @@ module Fontisan
314
335
  entry
315
336
  end
316
337
 
317
- # Build the glyf directory entry. origLength is the original (input)
318
- # glyf size; transformLength is the size of the WOFF2-transformed
319
- # glyf stream per spec section 5.1.
320
- def build_glyf_entry(orig_data, transformed_data)
338
+ # Build the glyf directory entry. origLength is the reconstructed
339
+ # glyf size (what a decoder will produce); transformLength is the
340
+ # size of the WOFF2-transformed glyf stream per spec section 5.1.
341
+ def build_glyf_entry(glyf_orig_length, transformed_data)
321
342
  entry = Woff2::Directory::Entry.new
322
343
  entry.tag = "glyf"
323
- entry.orig_length = orig_data.bytesize
344
+ entry.orig_length = glyf_orig_length
324
345
  entry.transform_length = transformed_data.bytesize
325
346
  entry.flags = entry.calculate_flags
326
347
  entry
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fontisan
4
- VERSION = "0.4.15"
4
+ VERSION = "0.4.16"
5
5
  end
@@ -133,14 +133,14 @@ module Fontisan
133
133
  pos += 4
134
134
  raise InvalidFontError, "Unsupported CollectionHeader version 0x#{version.to_s(16)}" unless version == 0x00010000
135
135
 
136
- num_fonts, pos = read_255_uint16(pos)
136
+ num_fonts, pos = UInt255.decode_at(@data, pos)
137
137
  font_entries = Array.new(num_fonts) do
138
- num_tables_f, pos2 = read_255_uint16(pos)
138
+ num_tables_f, pos2 = UInt255.decode_at(@data, pos)
139
139
  pos = pos2
140
140
  flavor = @data[pos, 4].unpack1("N")
141
141
  pos += 4
142
142
  indices = Array.new(num_tables_f) do
143
- idx, pos2 = read_255_uint16(pos)
143
+ idx, pos2 = UInt255.decode_at(@data, pos)
144
144
  pos = pos2
145
145
  idx
146
146
  end
@@ -201,26 +201,6 @@ module Fontisan
201
201
  end
202
202
  raise InvalidFontError, "UIntBase128 sequence exceeds 5 bytes"
203
203
  end
204
-
205
- def read_255_uint16(pos)
206
- code = @data.getbyte(pos)
207
- pos += 1
208
- case code
209
- when 0..252 then [code, pos]
210
- when 253
211
- v = @data.getbyte(pos)
212
- pos += 1
213
- [253 + v, pos]
214
- when 254
215
- v = @data[pos, 2].unpack1("n")
216
- pos += 2
217
- [v, pos]
218
- when 255
219
- v = @data[pos, 2].unpack1("n")
220
- pos += 2
221
- [v + 506, pos]
222
- end
223
- end
224
204
  end
225
205
  end
226
206
  end
@@ -238,7 +238,7 @@ module Fontisan
238
238
  def write_collection_directory(io, fonts, font_to_ckeys, ckey_to_index)
239
239
  # CollectionHeader
240
240
  io.write([0x00010000].pack("N")) # version 1.0
241
- io.write(encode_255_uint16(fonts.size))
241
+ io.write(UInt255.encode(fonts.size))
242
242
 
243
243
  # One CollectionFontEntry per font
244
244
  fonts.each_with_index do |font, fi|
@@ -254,12 +254,12 @@ module Fontisan
254
254
  ordered << "loca" if has_placeholder
255
255
  ordered = ordered.sort
256
256
 
257
- io.write(encode_255_uint16(ordered.size))
257
+ io.write(UInt255.encode(ordered.size))
258
258
  io.write([font_flavor(font)].pack("N"))
259
259
  ordered.each do |tag|
260
260
  ckey = font_keys[tag] || placeholder_key
261
261
  index = ckey_to_index.fetch(ckey)
262
- io.write(encode_255_uint16(index))
262
+ io.write(UInt255.encode(index))
263
263
  end
264
264
  end
265
265
  end
@@ -271,18 +271,6 @@ module Fontisan
271
271
  Constants::SFNT_VERSION_TRUETYPE
272
272
  end
273
273
  end
274
-
275
- def encode_255_uint16(value)
276
- if value < 253
277
- [value].pack("C")
278
- elsif value < 506
279
- [253, value - 253].pack("CC")
280
- elsif value < 65_536
281
- [254].pack("C") + [value].pack("n")
282
- else
283
- [255].pack("C") + [value - 506].pack("n")
284
- end
285
- end
286
274
  end
287
275
  end
288
276
  end
@@ -235,48 +235,20 @@ module Fontisan
235
235
  raise Fontisan::Error, "Invalid UIntBase128 encoding"
236
236
  end
237
237
 
238
- # Encode 255UInt16 value
239
- #
240
- # Used in transformed glyf table:
241
- # - 0-252: value itself (1 byte)
242
- # - 253: next byte + 253 (2 bytes)
243
- # - 254: next 2 bytes as big-endian (3 bytes)
244
- # - 255: next 2 bytes + 506 (3 bytes)
238
+ # Encode 255UInt16. Delegates to {UInt255} (single source of truth).
245
239
  #
246
240
  # @param value [Integer] Value to encode (0-65535)
247
241
  # @return [String] Binary encoded data
248
242
  def self.encode_255_uint16(value)
249
- if value < 253
250
- [value].pack("C")
251
- elsif value < 506
252
- [253, value - 253].pack("C*")
253
- elsif value < 65536
254
- [254].pack("C") + [value].pack("n")
255
- else
256
- [255].pack("C") + [value - 506].pack("n")
257
- end
243
+ UInt255.encode(value)
258
244
  end
259
245
 
260
- # Decode 255UInt16 from IO
246
+ # Decode 255UInt16 from IO. Delegates to {UInt255}.
261
247
  #
262
248
  # @param io [IO] Input stream
263
249
  # @return [Integer] Decoded value
264
250
  def self.decode_255_uint16(io)
265
- first = io.read(1)&.unpack1("C")
266
- return nil unless first
267
-
268
- case first
269
- when 0..252
270
- first
271
- when 253
272
- second = io.read(1)&.unpack1("C")
273
- 253 + second
274
- when 254
275
- io.read(2)&.unpack1("n")
276
- when 255
277
- value = io.read(2)&.unpack1("n")
278
- value + 506
279
- end
251
+ UInt255.decode(io)
280
252
  end
281
253
  end
282
254
  end
@@ -52,12 +52,6 @@ module Fontisan
52
52
  # the 'flags' field of the head table ... to indicate that a recreated
53
53
  # font file was subjected to lossless modifying transform."
54
54
  #
55
- # Also forces head.indexToLocFormat=0 when the glyf/loca tables are
56
- # transformed, because Chrome's OTS only accepts WOFF2 glyf
57
- # indexFormat=0 (see GlyfLocaTransform). For the reconstructed font
58
- # to be self-consistent, head.indexToLocFormat must match the loca
59
- # format that the decoder will produce (always short, format=0).
60
- #
61
55
  # Uses the model-driven Head BinData record so the bits are set via a
62
56
  # named attribute on a typed object, not via raw byte slicing.
63
57
  def self.mark_lossless_modifying!(table_data)
@@ -65,7 +59,6 @@ module Fontisan
65
59
 
66
60
  head = Tables::Head.read(table_data["head"])
67
61
  head.flags |= Tables::Head::FLAG_LOSSLESS_MODIFYING
68
- head.index_to_loc_format = 0
69
62
  table_data["head"] = head.to_binary_s
70
63
  end
71
64
  end
@@ -143,7 +143,7 @@ module Fontisan
143
143
  end_pts = []
144
144
  cumulative = -1
145
145
  num_contours.times do
146
- pts_of_contour = read_255_uint16(streams[:n_points])
146
+ pts_of_contour = UInt255.decode(streams[:n_points])
147
147
  cumulative += pts_of_contour
148
148
  end_pts << cumulative
149
149
  end
@@ -169,7 +169,7 @@ module Fontisan
169
169
  end
170
170
 
171
171
  # Step 4-5: read instructionLength from glyphStream, bytes from instructionStream.
172
- inst_len = read_255_uint16(streams[:glyph])
172
+ inst_len = UInt255.decode(streams[:glyph])
173
173
  instructions = streams[:instructions].read(inst_len)
174
174
 
175
175
  # Bbox: emit explicit bbox if bboxBitmap bit is set for this glyph,
@@ -209,7 +209,7 @@ module Fontisan
209
209
 
210
210
  instructions = String.new(encoding: Encoding::BINARY)
211
211
  if have_instructions
212
- inst_len = read_255_uint16(streams[:glyph])
212
+ inst_len = UInt255.decode(streams[:glyph])
213
213
  instructions = streams[:instructions].read(inst_len)
214
214
  end
215
215
 
@@ -252,26 +252,6 @@ module Fontisan
252
252
  bytes ? bytes.bytes : Array.new(n_bytes, 0)
253
253
  end
254
254
 
255
- def read_255_uint16(io)
256
- return 0 if io.eof?
257
-
258
- code = io.read(1)&.unpack1("C")
259
- return 0 unless code
260
-
261
- case code
262
- when 0..252 then code
263
- when 253
264
- b = io.read(1)&.unpack1("C") || 0
265
- 253 + b
266
- when 254
267
- io.read(2)&.unpack1("n") || 0
268
-
269
- when 255
270
- v = io.read(2)&.unpack1("n") || 0
271
- v + 506
272
- end
273
- end
274
-
275
255
  def read_uint16_io(io)
276
256
  io.read(2)&.unpack1("n") || 0
277
257
  end
@@ -127,7 +127,7 @@ module Fontisan
127
127
  # nPoints stream: per-contour point counts (NOT endPtsOfContours).
128
128
  prev_end = -1
129
129
  end_pts.each do |ep|
130
- s.n_points << encode_255_uint16(ep - prev_end)
130
+ s.n_points << UInt255.encode(ep - prev_end)
131
131
  prev_end = ep
132
132
  end
133
133
 
@@ -157,7 +157,7 @@ module Fontisan
157
157
  end
158
158
 
159
159
  # glyphStream carries per-glyph instructionLength; bytes go to instructionStream
160
- s.glyph << encode_255_uint16(instructions.bytesize)
160
+ s.glyph << UInt255.encode(instructions.bytesize)
161
161
  s.instructions << instructions
162
162
 
163
163
  # Spec: simple glyphs omit bbox when it matches calculated bounds.
@@ -191,7 +191,7 @@ module Fontisan
191
191
  if have_instructions
192
192
  inst_len = io.read(2).unpack1("n")
193
193
  instructions = io.read(inst_len)
194
- s.glyph << encode_255_uint16(instructions.bytesize)
194
+ s.glyph << UInt255.encode(instructions.bytesize)
195
195
  s.instructions << instructions
196
196
  end
197
197
 
@@ -255,10 +255,11 @@ module Fontisan
255
255
  out << [0].pack("S>") # version
256
256
  out << [(s.has_overlap? ? 1 : 0)].pack("S>") # optionFlags
257
257
  out << [@num_glyphs].pack("S>")
258
- # Always emit indexFormat=0 per Chrome OTS requirement. WOFF2 spec
259
- # section 5.1 allows the source's indexToLocFormat, but Chrome's
260
- # OTS silently rejects any value other than 0.
261
- out << [0].pack("S>")
258
+ # Emit the source's indexFormat. The earlier "always 0" override
259
+ # (commit 5f7e32d) was based on a misdiagnosis Chrome's OTS
260
+ # accepts both 0 and 1, but short loca (0) can't address glyf
261
+ # offsets > 0x20000 bytes, so large fonts MUST use 1.
262
+ out << [@source_index_format].pack("S>")
262
263
  out << [s.n_contour.bytesize].pack("L>")
263
264
  out << [s.n_points.bytesize].pack("L>")
264
265
  out << [s.flags.bytesize].pack("L>")
@@ -313,18 +314,6 @@ module Fontisan
313
314
 
314
315
  [xs.min, ys.min, xs.max, ys.max]
315
316
  end
316
-
317
- def encode_255_uint16(value)
318
- if value < 253
319
- [value].pack("C")
320
- elsif value < 506
321
- [253, value - 253].pack("CC")
322
- elsif value < 65_536
323
- [254].pack("C") + [value].pack("n")
324
- else
325
- [255].pack("C") + [value - 506].pack("n")
326
- end
327
- end
328
317
  end
329
318
  end
330
319
  end
@@ -46,7 +46,7 @@ glyf_lsbs = nil)
46
46
  if (flags & HMTX_FLAG_EXPLICIT_ADVANCE_WIDTHS).zero?
47
47
  # Proportional encoding - read deltas
48
48
  # First advance width is explicit
49
- first_advance = read_255_uint16(io)
49
+ first_advance = UInt255.decode(io)
50
50
  advance_widths << first_advance
51
51
 
52
52
  # Remaining are deltas from previous
@@ -57,7 +57,7 @@ glyf_lsbs = nil)
57
57
  else
58
58
  # Explicit advance widths in transformed format
59
59
  num_h_metrics.times do
60
- advance_widths << read_255_uint16(io)
60
+ advance_widths << UInt255.decode(io)
61
61
  end
62
62
  end
63
63
 
@@ -88,31 +88,6 @@ glyf_lsbs = nil)
88
88
  build_hmtx_table(advance_widths, lsbs, num_h_metrics, num_glyphs)
89
89
  end
90
90
 
91
- # Read variable-length 255UInt16 integer
92
- #
93
- # Format from WOFF2 spec:
94
- # - value < 253: one byte
95
- # - value == 253: 253 + next uint16
96
- # - value == 254: 253 * 2 + next uint16
97
- # - value == 255: 253 * 3 + next uint16
98
- #
99
- # @param io [StringIO] Input stream
100
- # @return [Integer] Decoded value
101
- def self.read_255_uint16(io)
102
- code = read_uint8(io)
103
-
104
- case code
105
- when 255
106
- 759 + read_uint16(io) # 253 * 3 + value
107
- when 254
108
- 506 + read_uint16(io) # 253 * 2 + value
109
- when 253
110
- 253 + read_uint16(io)
111
- else
112
- code
113
- end
114
- end
115
-
116
91
  # Build standard hmtx table format
117
92
  #
118
93
  # Standard hmtx format:
@@ -401,7 +401,7 @@ num_glyphs)
401
401
 
402
402
  # Write advance widths using proportional encoding
403
403
  # First advance width is explicit
404
- data << encode_255_uint16(advance_widths[0])
404
+ data << UInt255.encode(advance_widths[0])
405
405
 
406
406
  # Remaining advance widths as deltas
407
407
  (1...num_h_metrics).each do |i|
@@ -473,7 +473,7 @@ num_glyphs)
473
473
  prev_pt = -1
474
474
  glyph[:end_pts].each do |pt|
475
475
  delta = pt - prev_pt - 1
476
- n_points_stream << encode_255_uint16(delta)
476
+ n_points_stream << UInt255.encode(delta)
477
477
  prev_pt = pt
478
478
  end
479
479
 
@@ -488,7 +488,7 @@ num_glyphs)
488
488
  glyph[:bbox].each { |v| bbox_stream << [v].pack("n") }
489
489
 
490
490
  # Write instructions
491
- instruction_stream << encode_255_uint16(glyph[:instructions].bytesize)
491
+ instruction_stream << UInt255.encode(glyph[:instructions].bytesize)
492
492
  instruction_stream << glyph[:instructions] if glyph[:instructions].bytesize.positive?
493
493
 
494
494
  when :composite
@@ -569,22 +569,6 @@ num_glyphs)
569
569
  end
570
570
  end
571
571
 
572
- # Encode 255UInt16 value
573
- #
574
- # @param value [Integer] Value to encode
575
- # @return [String] Encoded bytes
576
- def encode_255_uint16(value)
577
- if value < 253
578
- [value].pack("C")
579
- elsif value < 506
580
- [253, value - 253].pack("CC")
581
- elsif value < 65536
582
- [254].pack("C") + [value].pack("n")
583
- else
584
- [255].pack("C") + [value - 506].pack("n")
585
- end
586
- end
587
-
588
572
  # Read signed 16-bit integer
589
573
  #
590
574
  # @param io [StringIO] Input stream
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Fontisan
6
+ module Woff2
7
+ # 255UInt16 variable-length encoding per WOFF2 spec section 3.1.
8
+ #
9
+ # Single source of truth for encoding and decoding this data type. All
10
+ # other WOFF2 code MUST delegate to this module — the previous inline
11
+ # copies had the code-byte mapping inverted for values ≥ 253.
12
+ #
13
+ # Encoding table (per W3C spec pseudocode):
14
+ #
15
+ # value range | encoding | bytes
16
+ # ----------------|-----------------------|------
17
+ # 0 .. 252 | literal | 1
18
+ # 253 .. 505 | code 255 + (v - 253) | 2
19
+ # 506 .. 761 | code 254 + (v - 506) | 2
20
+ # 762 .. 65535 | code 253 + uint16 | 3
21
+ #
22
+ # Decoding (inverse):
23
+ #
24
+ # code byte | meaning
25
+ # ----------|--------------------------------
26
+ # 0 .. 252 | literal value
27
+ # 253 | read uint16 → value
28
+ # 254 | read 1 byte → value + 506
29
+ # 255 | read 1 byte → value + 253
30
+ module UInt255
31
+ WORD_CODE = 253
32
+ ONE_MORE_BYTE_CODE1 = 255 # adds 253
33
+ ONE_MORE_BYTE_CODE2 = 254 # adds 506
34
+
35
+ MAX_VALUE = 65_535
36
+
37
+ # Encode a value (0..65535) into a 1-3 byte binary string.
38
+ #
39
+ # @param value [Integer]
40
+ # @return [String] binary-encoded bytes
41
+ # @raise [ArgumentError] if value is out of range
42
+ def self.encode(value)
43
+ case value
44
+ when 0..252
45
+ [value].pack("C")
46
+ when 253..505
47
+ [ONE_MORE_BYTE_CODE1, value - 253].pack("C*")
48
+ when 506..761
49
+ [ONE_MORE_BYTE_CODE2, value - 506].pack("C*")
50
+ when 762..MAX_VALUE
51
+ [WORD_CODE].pack("C") + [value].pack("n")
52
+ else
53
+ raise ArgumentError,
54
+ "255UInt16 requires 0 <= value <= #{MAX_VALUE}, got #{value}"
55
+ end
56
+ end
57
+
58
+ # Decode a 255UInt16 value from an IO stream. Reads 1-3 bytes.
59
+ #
60
+ # @param io [IO, StringIO] input stream positioned at the code byte
61
+ # @return [Integer, nil] decoded value, or nil if the stream is empty
62
+ def self.decode(io)
63
+ code = io.read(1)&.unpack1("C")
64
+ return nil unless code
65
+
66
+ case code
67
+ when 0..252
68
+ code
69
+ when WORD_CODE
70
+ io.read(2)&.unpack1("n")
71
+ when ONE_MORE_BYTE_CODE2
72
+ 506 + (io.read(1)&.unpack1("C") || 0)
73
+ when ONE_MORE_BYTE_CODE1
74
+ 253 + (io.read(1)&.unpack1("C") || 0)
75
+ end
76
+ end
77
+
78
+ # Decode from a binary String at a given position. Returns the value
79
+ # and the new cursor position. Used by callers that index into a
80
+ # flat String rather than wrapping it in a StringIO.
81
+ #
82
+ # @param data [String] binary data
83
+ # @param pos [Integer] byte offset of the code byte
84
+ # @return [Array(Integer, Integer)] [value, new_pos]
85
+ def self.decode_at(data, pos)
86
+ code = data.getbyte(pos)
87
+ pos += 1
88
+ case code
89
+ when 0..252
90
+ [code, pos]
91
+ when WORD_CODE
92
+ [data[pos, 2].unpack1("n"), pos + 2]
93
+ when ONE_MORE_BYTE_CODE2
94
+ [506 + data.getbyte(pos), pos + 1]
95
+ when ONE_MORE_BYTE_CODE1
96
+ [253 + data.getbyte(pos), pos + 1]
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -13,6 +13,7 @@ module Fontisan
13
13
  autoload :HmtxTransformer, "fontisan/woff2/hmtx_transformer"
14
14
  autoload :TableTransformer, "fontisan/woff2/table_transformer"
15
15
  autoload :TripletCodec, "fontisan/woff2/triplet_codec"
16
+ autoload :UInt255, "fontisan/woff2/uint255"
16
17
  autoload :Woff2Header, "fontisan/woff2/header"
17
18
  end
18
19
  end
@@ -732,22 +732,6 @@ module Fontisan
732
732
  self.class.read_uint_base128_from_io(io)
733
733
  end
734
734
 
735
- # Read 255UInt16 variable-length integer
736
- def read_255_uint16(io)
737
- code = io.read(1).unpack1("C")
738
-
739
- case code
740
- when 0..252
741
- code
742
- when 253
743
- 253 + io.read(1).unpack1("C")
744
- when 254
745
- io.read(2).unpack1("n")
746
- when 255
747
- io.read(2).unpack1("n") + 506
748
- end
749
- end
750
-
751
735
  # Calculate offset table fields
752
736
  def calculate_offset_table_fields(num_tables)
753
737
  entry_selector = (Math.log(num_tables) / Math.log(2)).floor
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.15
4
+ version: 0.4.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -729,6 +729,7 @@ files:
729
729
  - lib/fontisan/woff2/hmtx_transformer.rb
730
730
  - lib/fontisan/woff2/table_transformer.rb
731
731
  - lib/fontisan/woff2/triplet_codec.rb
732
+ - lib/fontisan/woff2/uint255.rb
732
733
  - lib/fontisan/woff2_collection.rb
733
734
  - lib/fontisan/woff2_font.rb
734
735
  - lib/fontisan/woff_font.rb