Class: Fontisan::Woff2::GlyfLocaReconstruct

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/woff2/glyf_loca_reconstruct.rb

Overview

Reconstructs glyf and loca tables from the WOFF2 transformed glyf stream per spec section 5.1. This is the decoder counterpart of GlyfLocaTransform.

The transformed glyf table is split into 7 streams preceded by a 36-byte header (uint16 version + uint16 optionFlags + uint16 numGlyphs

  • uint16 indexFormat + 7 × uint32 stream sizes). An optional overlapSimpleBitmap follows when optionFlags bit 0 is set.

Reference: W3C WOFF2 spec, section 5.1.

Constant Summary collapse

FLAG_ON_CURVE =

TrueType simple-glyph flag bits per OpenType spec.

0x01
FLAG_X_SHORT =
0x02
FLAG_Y_SHORT =
0x04
FLAG_REPEAT =
0x08
FLAG_X_SAME_OR_POS =
0x10
FLAG_Y_SAME_OR_POS =
0x20
FLAG_OVERLAP_SIMPLE =
0x40
ARG_1_AND_2_ARE_WORDS =

TrueType composite-glyph flag bits.

0x0001
WE_HAVE_A_SCALE =
0x0008
MORE_COMPONENTS =
0x0020
WE_HAVE_AN_X_AND_Y_SCALE =
0x0040
WE_HAVE_A_TWO_BY_TWO =
0x0080
WE_HAVE_INSTRUCTIONS =
0x0100
HEADER_SIZE =

8-byte header + 7 × 4-byte stream sizes.

36

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(transformed_glyf:, num_glyphs:, index_format:) ⇒ GlyfLocaReconstruct

Returns a new instance of GlyfLocaReconstruct.

Parameters:

  • transformed_glyf (String)

    bytes of the transformed glyf table

  • num_glyphs (Integer)

    from maxp

  • index_format (Integer)

    0 (short) or 1 (long), from head



43
44
45
46
47
# File 'lib/fontisan/woff2/glyf_loca_reconstruct.rb', line 43

def initialize(transformed_glyf:, num_glyphs:, index_format:)
  @data = transformed_glyf
  @num_glyphs = num_glyphs
  @index_format = index_format
end

Instance Attribute Details

#index_formatObject (readonly)

Returns the value of attribute index_format.



38
39
40
# File 'lib/fontisan/woff2/glyf_loca_reconstruct.rb', line 38

def index_format
  @index_format
end

#num_glyphsObject (readonly)

Returns the value of attribute num_glyphs.



38
39
40
# File 'lib/fontisan/woff2/glyf_loca_reconstruct.rb', line 38

def num_glyphs
  @num_glyphs
end

Instance Method Details

#reconstructHash{Symbol => String}

Reconstruct glyf and loca tables.

Per OpenType glyf table spec, loca offsets must be even (short format) or multiples of 4 (long format). Each reconstructed glyph is padded to the loca-format alignment boundary so the next glyph starts at a valid offset. Without this padding, Chrome's OTS rejects the font with "Failed to convert WOFF 2.0 font to SFNT" because glyf.origLength understates the padded size every conformant decoder produces.

Returns:

  • (Hash{Symbol => String})

    { glyf:, loca: }



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/fontisan/woff2/glyf_loca_reconstruct.rb', line 60

def reconstruct
  header = parse_header
  streams = read_streams(header)

  glyf = String.new(encoding: Encoding::BINARY)
  offsets = [0]
  # Short loca (indexFormat=0) stores offset/2 as uint16, so glyph
  # offsets must be even — pad to 2-byte boundary. Long loca
  # (indexFormat=1) has no alignment requirement (fontTools does
  # not pad). Matching fontTools exactly is required: Chrome OTS
  # rejects when glyf.origLength doesn't equal the decoder's output.
  align = @index_format.zero? ? 2 : 1

  num_glyphs.times do |glyph_id|
    glyph = decode_glyph(glyph_id, streams)
    glyf << glyph
    if align > 1
      remainder = glyf.bytesize % align
      glyf << ("\x00" * (align - remainder)) if remainder.positive?
    end
    offsets << glyf.bytesize
  end

  { glyf:, loca: build_loca(offsets) }
end