Class: Fontisan::Tables::Loca
- Inherits:
-
Binary::BaseRecord
- Object
- BinData::Record
- Binary::BaseRecord
- Fontisan::Tables::Loca
- Extended by:
- Registered
- 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 https://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 included from Registered
Methods inherited from Binary::BaseRecord
Instance Attribute Details
#format ⇒ Integer (readonly)
Format of the loca table (0 = short, 1 = long)
63 64 65 |
# File 'lib/fontisan/tables/loca.rb', line 63 def format @format end |
#num_glyphs ⇒ Integer (readonly)
Total number of glyphs from maxp table
67 68 69 |
# File 'lib/fontisan/tables/loca.rb', line 67 def num_glyphs @num_glyphs end |
#offsets ⇒ Array<Integer> (readonly)
Parsed offsets array
59 60 61 |
# File 'lib/fontisan/tables/loca.rb', line 59 def offsets @offsets end |
#raw_data ⇒ Object
Store the raw data for deferred parsing
55 56 57 |
# File 'lib/fontisan/tables/loca.rb', line 55 def raw_data @raw_data end |
Class Method Details
.read(io) ⇒ Loca
Override read to capture raw data
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/fontisan/tables/loca.rb', line 73 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.
167 168 169 170 |
# File 'lib/fontisan/tables/loca.rb', line 167 def empty?(glyph_id) size = size_of(glyph_id) size&.zero? end |
#expected_size ⇒ Integer?
Get the expected size for this table
196 197 198 199 200 201 202 203 204 205 |
# File 'lib/fontisan/tables/loca.rb', line 196 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)
189 190 191 |
# File 'lib/fontisan/tables/loca.rb', line 189 def long_format? format == FORMAT_LONG end |
#offset_for(glyph_id) ⇒ Integer?
Get the offset for a specific glyph ID in the glyf table
126 127 128 129 130 131 132 |
# File 'lib/fontisan/tables/loca.rb', line 126 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.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/fontisan/tables/loca.rb', line 97 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
175 176 177 |
# File 'lib/fontisan/tables/loca.rb', line 175 def parsed? !@offsets.nil? end |
#short_format? ⇒ Boolean
Check if using short format (format 0)
182 183 184 |
# File 'lib/fontisan/tables/loca.rb', line 182 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).
147 148 149 150 151 152 153 |
# File 'lib/fontisan/tables/loca.rb', line 147 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 |