Module: Fontisan::Woff2::TripletCodec

Defined in:
lib/fontisan/woff2/triplet_codec.rb

Overview

Variable-length coordinate codec for the WOFF2 glyf transform.

Per WOFF2 spec section 5.2, each (dx, dy, on_curve) point is encoded as one flag byte plus 1-4 payload bytes ("triplets"). The flag byte's high bit is the on-curve flag; the low 7 bits select one of 128 encoding variants. Variants are chosen by coordinate magnitude so small deltas cost 1-2 bytes and only very large deltas cost 4.

Reference: WOFF2 spec section 5.2 (triplet encoding table).

Constant Summary collapse

ON_CURVE_BIT =
0x00
OFF_CURVE_BIT =
0x80

Class Method Summary collapse

Class Method Details

.decode(flag, payload) ⇒ Array(Integer, Integer, Boolean)

Decode one triplet given the flag byte and a cursor over payload bytes.

Parameters:

  • flag (Integer)

    flag byte

  • payload (Array<Integer>)

    payload bytes following the flag

Returns:

  • (Array(Integer, Integer, Boolean))

    dx, dy, on_curve



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/fontisan/woff2/triplet_codec.rb', line 52

def self.decode(flag, payload)
  on_curve = (flag & OFF_CURVE_BIT).zero?
  idx = flag & 0x7F

  dx, dy = if idx < 10
             decode_y_only(idx, payload)
           elsif idx < 20
             decode_x_only(idx, payload)
           elsif idx < 84
             decode_nibble_pair(idx, payload)
           elsif idx < 120
             decode_byte_pair(idx, payload)
           elsif idx < 124
             decode_12_bit_pair(idx, payload)
           else
             decode_16_bit_pair(idx, payload)
           end
  [dx, dy, on_curve]
end

.encode(dx, dy, on_curve:) ⇒ Array(Integer, Array<Integer>)

Encode a single (dx, dy) delta with the given on-curve flag.

Parameters:

  • dx (Integer)

    X delta (signed, -65535..65535)

  • dy (Integer)

    Y delta (signed, -65535..65535)

  • on_curve (Boolean)

    true if this is an on-curve point

Returns:

  • (Array(Integer, Array<Integer>))

    flag byte and payload bytes



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/fontisan/woff2/triplet_codec.rb', line 24

def self.encode(dx, dy, on_curve:)
  on_curve_bit = on_curve ? ON_CURVE_BIT : OFF_CURVE_BIT
  abs_x = dx.abs
  abs_y = dy.abs
  x_sign_bit = dx.negative? ? 0 : 1
  y_sign_bit = dy.negative? ? 0 : 1
  xy_sign_bits = x_sign_bit + (2 * y_sign_bit)

  if dx.zero? && abs_y < 1280
    encode_y_only(on_curve_bit, abs_y, y_sign_bit)
  elsif dy.zero? && abs_x < 1280
    encode_x_only(on_curve_bit, abs_x, x_sign_bit)
  elsif abs_x < 65 && abs_y < 65
    encode_nibble_pair(on_curve_bit, abs_x, abs_y, xy_sign_bits)
  elsif abs_x < 769 && abs_y < 769
    encode_byte_pair(on_curve_bit, abs_x, abs_y, xy_sign_bits)
  elsif abs_x < 4096 && abs_y < 4096
    encode_12_bit_pair(on_curve_bit, abs_x, abs_y, xy_sign_bits)
  else
    encode_16_bit_pair(on_curve_bit, abs_x, abs_y, xy_sign_bits)
  end
end