Class: Fontisan::Collection::OffsetCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/collection/offset_calculator.rb

Overview

OffsetCalculator calculates file offsets for TTC/OTC structure

Single responsibility: Calculate all file offsets for the collection structure including TTC header, offset table, font directories, and table data. Handles 4-byte alignment requirements.

TTC/OTC Structure:

  • TTC Header (12 bytes)
  • Offset Table (4 bytes per font)
  • Font 0 Table Directory
  • Font 1 Table Directory
  • ...
  • Shared Tables
  • Unique Tables

Examples:

Calculate offsets

calculator = OffsetCalculator.new(sharing_map, fonts)
offsets = calculator.calculate
header_offset = offsets[:header_offset]
font_directory_offsets = offsets[:font_directory_offsets]

Constant Summary collapse

TABLE_ALIGNMENT =

Alignment requirement for tables (4 bytes)

4
TTC_HEADER_SIZE =

TTC header size (12 bytes)

12
FONT_OFFSET_SIZE =

Size of each font offset entry (4 bytes)

4
FONT_DIRECTORY_HEADER_SIZE =

Size of font directory header (12 bytes: sfnt_version, num_tables, searchRange, entrySelector, rangeShift)

12
TABLE_DIRECTORY_ENTRY_SIZE =

Size of each table directory entry (16 bytes: tag, checksum, offset, length)

16

Instance Method Summary collapse

Constructor Details

#initialize(sharing_map, fonts) ⇒ OffsetCalculator

Initialize calculator

Parameters:

Raises:

  • (ArgumentError)

    if parameters are invalid



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/fontisan/collection/offset_calculator.rb', line 46

def initialize(sharing_map, fonts)
  raise ArgumentError, "sharing_map cannot be nil" if sharing_map.nil?

  if fonts.nil? || fonts.empty?
    raise ArgumentError,
          "fonts cannot be nil or empty"
  end

  @sharing_map = sharing_map
  @fonts = fonts
  @offsets = {}
end

Instance Method Details

#calculateHash

Calculate all offsets for the collection

Returns:

  • (Hash)

    Complete offset map with:

    • :header_offset [Integer] - TTC header offset (always 0)
    • :offset_table_offset [Integer] - Offset table offset (always 12)
    • :font_directory_offsets [Array] - Offset to each font's directory
    • :table_offsets [Hash] - Map of canonical_id to file offset
    • :font_table_directories [Hash] - Per-font table directory info


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/fontisan/collection/offset_calculator.rb', line 67

def calculate
  @offsets = {
    header_offset: 0,
    offset_table_offset: TTC_HEADER_SIZE,
    font_directory_offsets: [],
    table_offsets: {},
    font_table_directories: {},
  }

  # Calculate offset after TTC header and offset table
  current_offset = TTC_HEADER_SIZE + (@fonts.size * FONT_OFFSET_SIZE)

  # Calculate offsets for each font's table directory
  calculate_font_directory_offsets(current_offset)

  # Calculate offsets for table data
  calculate_table_data_offsets

  @offsets
end

#font_directory_offset(font_index) ⇒ Integer?

Get offset for specific font's directory

Parameters:

  • font_index (Integer)

    Font index

Returns:

  • (Integer, nil)

    Offset or nil if not calculated



92
93
94
95
# File 'lib/fontisan/collection/offset_calculator.rb', line 92

def font_directory_offset(font_index)
  calculate unless @offsets.key?(:font_directory_offsets) && @offsets[:font_directory_offsets].any?
  @offsets[:font_directory_offsets][font_index]
end

#table_offset(canonical_id) ⇒ Integer?

Get offset for specific table

Parameters:

  • canonical_id (String)

    Canonical table ID

Returns:

  • (Integer, nil)

    Offset or nil if not found



101
102
103
104
# File 'lib/fontisan/collection/offset_calculator.rb', line 101

def table_offset(canonical_id)
  calculate unless @offsets.key?(:table_offsets) && @offsets[:table_offsets].any?
  @offsets[:table_offsets][canonical_id]
end