Class: Fontisan::Tables::Loca
- Inherits:
-
Binary::BaseRecord
- Object
- BinData::Record
- Binary::BaseRecord
- Fontisan::Tables::Loca
- Defined in:
- lib/fontisan/tables/loca.rb
Overview
Parser for the ‘loca’ (Index to Location) table
The loca table provides offsets to glyph data in the glyf table. Each glyph has an entry in this table indicating where its data begins in the glyf table. An additional entry marks the end of the last glyph’s data.
The table has two formats:
-
Short format (0): uint16 offsets divided by 2 (actual offset = value × 2)
-
Long format (1): uint32 offsets used as-is
The format is determined by head.indexToLocFormat:
-
0 = short format (uint16, multiply by 2)
-
1 = long format (uint32, use as-is)
The table always contains (numGlyphs + 1) offsets, where the last offset marks the end of the last glyph’s data in the glyf table.
The table is context-dependent and requires:
-
indexToLocFormat from head table (format selection)
-
numGlyphs from maxp table (number of offsets to read)
Reference: OpenType specification, loca table docs.microsoft.com/en-us/typography/opentype/spec/loca
Constant Summary collapse
- FORMAT_SHORT =
Short format constant (from head.indexToLocFormat)
0- FORMAT_LONG =
Long format constant (from head.indexToLocFormat)
1
Instance Attribute Summary collapse
-
#format ⇒ Integer
readonly
Format of the loca table (0 = short, 1 = long).
-
#num_glyphs ⇒ Integer
readonly
Total number of glyphs from maxp table.
-
#offsets ⇒ Array<Integer>
readonly
Parsed offsets array.
-
#raw_data ⇒ Object
Store the raw data for deferred parsing.
Class Method Summary collapse
-
.read(io) ⇒ Loca
Override read to capture raw data.
Instance Method Summary collapse
-
#empty?(glyph_id) ⇒ Boolean?
Check if a glyph has no outline data.
-
#expected_size ⇒ Integer?
Get the expected size for this table.
-
#long_format? ⇒ Boolean
Check if using long format (format 1).
-
#offset_for(glyph_id) ⇒ Integer?
Get the offset for a specific glyph ID in the glyf table.
-
#parse_with_context(index_to_loc_format, num_glyphs) ⇒ Object
Parse the table with font context.
-
#parsed? ⇒ Boolean
Check if the table has been parsed with context.
-
#short_format? ⇒ Boolean
Check if using short format (format 0).
-
#size_of(glyph_id) ⇒ Integer?
Calculate the size of glyph data for a specific glyph ID.
Methods inherited from Binary::BaseRecord
Instance Attribute Details
#format ⇒ Integer (readonly)
Format of the loca table (0 = short, 1 = long)
62 63 64 |
# File 'lib/fontisan/tables/loca.rb', line 62 def format @format end |
#num_glyphs ⇒ Integer (readonly)
Total number of glyphs from maxp table
66 67 68 |
# File 'lib/fontisan/tables/loca.rb', line 66 def num_glyphs @num_glyphs end |
#offsets ⇒ Array<Integer> (readonly)
Parsed offsets array
58 59 60 |
# File 'lib/fontisan/tables/loca.rb', line 58 def offsets @offsets end |
#raw_data ⇒ Object
Store the raw data for deferred parsing
54 55 56 |
# File 'lib/fontisan/tables/loca.rb', line 54 def raw_data @raw_data end |
Class Method Details
.read(io) ⇒ Loca
Override read to capture raw data
72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/fontisan/tables/loca.rb', line 72 def self.read(io) instance = new # Handle nil or empty data gracefully instance.raw_data = if io.nil? "".b elsif io.is_a?(String) io else io.read || "".b end instance end |
Instance Method Details
#empty?(glyph_id) ⇒ Boolean?
Check if a glyph has no outline data
A glyph is empty when its size is 0, which occurs when consecutive offsets are equal. Empty glyphs are used for space characters and other non-visible glyphs.
166 167 168 169 |
# File 'lib/fontisan/tables/loca.rb', line 166 def empty?(glyph_id) size = size_of(glyph_id) size&.zero? end |
#expected_size ⇒ Integer?
Get the expected size for this table
195 196 197 198 199 200 201 202 203 204 |
# File 'lib/fontisan/tables/loca.rb', line 195 def expected_size return nil unless parsed? offset_count = num_glyphs + 1 if short_format? offset_count * 2 # uint16 else offset_count * 4 # uint32 end end |
#long_format? ⇒ Boolean
Check if using long format (format 1)
188 189 190 |
# File 'lib/fontisan/tables/loca.rb', line 188 def long_format? format == FORMAT_LONG end |
#offset_for(glyph_id) ⇒ Integer?
Get the offset for a specific glyph ID in the glyf table
125 126 127 128 129 130 131 |
# File 'lib/fontisan/tables/loca.rb', line 125 def offset_for(glyph_id) raise "Table not parsed. Call parse_with_context first." unless @offsets return nil if glyph_id >= num_glyphs || glyph_id.negative? offsets[glyph_id] end |
#parse_with_context(index_to_loc_format, num_glyphs) ⇒ Object
Parse the table with font context
This method must be called after reading the table data, providing the indexToLocFormat from head and numGlyphs from maxp.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/fontisan/tables/loca.rb', line 96 def parse_with_context(index_to_loc_format, num_glyphs) validate_context_params(index_to_loc_format, num_glyphs) @format = index_to_loc_format @num_glyphs = num_glyphs io = StringIO.new(raw_data) io.set_encoding(Encoding::BINARY) # Number of offsets is numGlyphs + 1 (extra offset marks end of last glyph) offset_count = num_glyphs + 1 @offsets = if short_format? parse_short_offsets(io, offset_count) else parse_long_offsets(io, offset_count) end validate_parsed_data!(io, offset_count) end |
#parsed? ⇒ Boolean
Check if the table has been parsed with context
174 175 176 |
# File 'lib/fontisan/tables/loca.rb', line 174 def parsed? !@offsets.nil? end |
#short_format? ⇒ Boolean
Check if using short format (format 0)
181 182 183 |
# File 'lib/fontisan/tables/loca.rb', line 181 def short_format? format == FORMAT_SHORT end |
#size_of(glyph_id) ⇒ Integer?
Calculate the size of glyph data for a specific glyph ID
The size is calculated as the difference between consecutive offsets: size = offsets[glyph_id + 1] - offsets
A size of 0 indicates an empty glyph (no outline data).
146 147 148 149 150 151 152 |
# File 'lib/fontisan/tables/loca.rb', line 146 def size_of(glyph_id) raise "Table not parsed. Call parse_with_context first." unless @offsets return nil if glyph_id >= num_glyphs || glyph_id.negative? offsets[glyph_id + 1] - offsets[glyph_id] end |