Class: Fontisan::OpenTypeFont

Inherits:
SfntFont
  • Object
show all
Defined in:
lib/fontisan/open_type_font.rb,
lib/fontisan/open_type_font_extensions.rb

Overview

Extensions to OpenTypeFont for table-based construction

Constant Summary collapse

PAGE_SIZE =

Page size for lazy loading alignment (typical filesystem page size)

4096

Constants inherited from SfntFont

SfntFont::PADDING_BYTES, SfntFont::SFNT_TABLE_CLASS_MAP, SfntFont::TABLE_CLASS_MAP

Instance Attribute Summary collapse

Attributes inherited from SfntFont

#io_source, #lazy_load_enabled, #loading_mode, #parsed_tables, #sfnt_tables, #table_data, #table_entry_cache

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SfntFont

#all_sfnt_tables, #close, #family_name, finalize, #find_table_entry, from_collection, #full_name, #has_table?, #head_table, #post_script_name, #preferred_family_name, #preferred_subfamily_name, #read_metadata_tables_batched, #read_table_data, #setup_finalizer, #sfnt_table, #subfamily_name, #table, #table_available?, #table_names, #to_file, #units_per_em, #update_checksum_adjustment_in_file, #update_checksum_adjustment_in_io

Instance Attribute Details

#page_cacheObject

Page cache for lazy loading (maps page_start_offset => page_data)



30
31
32
# File 'lib/fontisan/open_type_font.rb', line 30

def page_cache
  @page_cache
end

Class Method Details

.from_file(path, mode: LoadingModes::FULL, lazy: false) ⇒ OpenTypeFont

Read OpenType Font from a file

Parameters:

  • path (String)

    Path to the OTF file

  • mode (Symbol) (defaults to: LoadingModes::FULL)

    Loading mode (:metadata or :full, default: :full)

  • lazy (Boolean) (defaults to: false)

    If true, load tables on demand (default: false)

Returns:

Raises:

  • (ArgumentError)

    if path is nil or empty, or if mode is invalid

  • (Errno::ENOENT)

    if file does not exist

  • (RuntimeError)

    if file format is invalid



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
70
71
72
73
# File 'lib/fontisan/open_type_font.rb', line 44

def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
  if path.nil? || path.to_s.empty?
    raise ArgumentError,
          "path cannot be nil or empty"
  end
  raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)

  # Validate mode
  LoadingModes.validate_mode!(mode)

  File.open(path, "rb") do |io|
    font = read(io)
    font.initialize_storage
    font.loading_mode = mode
    font.lazy_load_enabled = lazy

    if lazy
      # Keep file handle open for lazy loading
      font.io_source = File.open(path, "rb")
      font.setup_finalizer
    else
      # Read tables upfront
      font.read_table_data(io)
    end

    font
  end
rescue BinData::ValidityError, EOFError => e
  raise "Invalid OTF file: #{e.message}"
end

.from_tables(tables) ⇒ OpenTypeFont

Create font from hash of tables

This is used during font conversion when we have tables but not a file.

Parameters:

  • tables (Hash<String, String>)

    Map of table tag to binary data

Returns:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/fontisan/open_type_font_extensions.rb', line 12

def self.from_tables(tables)
  # Create minimal header structure
  font = new
  font.initialize_storage
  font.loading_mode = LoadingModes::FULL

  # Store table data
  font.table_data = tables

  # Build header from tables
  num_tables = tables.size
  max_power = 0
  n = num_tables
  while n > 1
    n >>= 1
    max_power += 1
  end

  search_range = (1 << max_power) * 16
  entry_selector = max_power
  range_shift = (num_tables * 16) - search_range

  font.header.sfnt_version = 0x4F54544F # 'OTTO' for OpenType/CFF
  font.header.num_tables = num_tables
  font.header.search_range = search_range
  font.header.entry_selector = entry_selector
  font.header.range_shift = range_shift

  # Build table directory
  font.tables.clear
  tables.each_key do |tag|
    entry = TableDirectory.new
    entry.tag = tag
    entry.checksum = 0 # Will be calculated on write
    entry.offset = 0 # Will be calculated on write
    entry.table_length = tables[tag].bytesize
    font.tables << entry
  end

  font
end

Instance Method Details

#cff?Boolean

Check if font is CFF flavored

Returns:

  • (Boolean)

    true for OpenType fonts



107
108
109
# File 'lib/fontisan/open_type_font.rb', line 107

def cff?
  true
end

#initialize_storagevoid

This method returns an undefined value.

Initialize storage hashes

Extends base class to add page_cache for lazy loading.



80
81
82
83
# File 'lib/fontisan/open_type_font.rb', line 80

def initialize_storage
  super
  @page_cache = {}
end

#truetype?Boolean

Check if font is TrueType flavored

Returns:

  • (Boolean)

    false for OpenType fonts



100
101
102
# File 'lib/fontisan/open_type_font.rb', line 100

def truetype?
  false
end

#valid?Boolean

Validate format correctness

Extends base class to check for CFF table (OpenType-specific).

Returns:

  • (Boolean)

    true if the OTF format is valid, false otherwise



90
91
92
93
94
95
# File 'lib/fontisan/open_type_font.rb', line 90

def valid?
  return false unless super
  return false unless has_table?(Constants::CFF_TAG)

  true
end