Class: Fontisan::Woff2::CollectionDecoder

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

Overview

Decodes a WOFF2 font collection per spec section 4.2. This is the decoder counterpart of CollectionEncoder.

Layout parsed:

[WOFF2Header (48 bytes, flavor = 'ttcf')]
[TableDirectory]              # one entry per unique table
[CollectionDirectory]         # CollectionHeader + N CollectionFontEntry
[CompressedFontData]          # single brotli stream of all tables

Each CollectionFontEntry references tables in the TableDirectory via indices. The decoder yields one reconstructed font per entry, with glyf/loca reconstruction per spec section 5.1/5.3 applied.

Reference: W3C WOFF2 spec, section 4.2.

Defined Under Namespace

Classes: FontEntry, TableEntry

Constant Summary collapse

TTC_FLAVOR =

'ttcf'

0x74746366

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ CollectionDecoder

Returns a new instance of CollectionDecoder.

Parameters:

  • data (String)

    WOFF2 collection binary



32
33
34
# File 'lib/fontisan/woff2/collection_decoder.rb', line 32

def initialize(data)
  @data = data.dup.force_encoding(Encoding::BINARY)
end

Instance Method Details

#decodeArray<Hash{Symbol => Object}>

Decode the WOFF2 collection, returning one Hash per font containing the reconstructed table data ready to assemble into an SFNT.

Returns:

  • (Array<Hash{Symbol => Object}>)

    per-font: tables: {tag ⇒ bytes}



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/fontisan/woff2/collection_decoder.rb', line 41

def decode
  validate_signature!
  validate_collection_flavor!

  table_entries, post_dir_pos = read_table_directory
  font_entries, post_coll_pos = read_collection_directory(post_dir_pos)
  decompressed = decompress_table_data(post_coll_pos)

  # Replace each table entry's raw_bytes by slicing from the
  # decompressed stream at its cumulative offset.
  cursor = 0
  table_entries.each do |e|
    len = e.transform_length || e.orig_length
    e.raw_bytes = decompressed[cursor, len]
    cursor += len
  end

  # For each font, gather its tables and reconstruct glyf/loca when
  # the glyf was transformed.
  font_entries.map do |fe|
    font_tables = {}
    fe.table_indices.each do |idx|
      entry = table_entries.fetch(idx)
      font_tables[entry.tag] = entry.raw_bytes
    end
    reconstruct_glyf_loca!(font_tables) if font_tables.key?("glyf")
    { flavor: fe.flavor, tables: font_tables }
  end
end