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 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 inherited from Binary::BaseRecord
Instance Attribute Details
#format ⇒ Integer (readonly)
Format of the loca table (0 = short, 1 = long)
60 61 62 |
# File 'lib/fontisan/tables/loca.rb', line 60 def format @format end |
#num_glyphs ⇒ Integer (readonly)
Total number of glyphs from maxp table
64 65 66 |
# File 'lib/fontisan/tables/loca.rb', line 64 def num_glyphs @num_glyphs end |
#offsets ⇒ Array<Integer> (readonly)
Parsed offsets array
56 57 58 |
# File 'lib/fontisan/tables/loca.rb', line 56 def offsets @offsets end |
#raw_data ⇒ Object
Store the raw data for deferred parsing
52 53 54 |
# File 'lib/fontisan/tables/loca.rb', line 52 def raw_data @raw_data end |
Class Method Details
.read(io) ⇒ Loca
Override read to capture raw data
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/fontisan/tables/loca.rb', line 70 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.
164 165 166 167 |
# File 'lib/fontisan/tables/loca.rb', line 164 def empty?(glyph_id) size = size_of(glyph_id) size&.zero? end |
#expected_size ⇒ Integer?
Get the expected size for this table
193 194 195 196 197 198 199 200 201 202 |
# File 'lib/fontisan/tables/loca.rb', line 193 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)
186 187 188 |
# File 'lib/fontisan/tables/loca.rb', line 186 def long_format? format == FORMAT_LONG end |
#offset_for(glyph_id) ⇒ Integer?
Get the offset for a specific glyph ID in the glyf table
123 124 125 126 127 128 129 |
# File 'lib/fontisan/tables/loca.rb', line 123 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.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/fontisan/tables/loca.rb', line 94 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
172 173 174 |
# File 'lib/fontisan/tables/loca.rb', line 172 def parsed? !@offsets.nil? end |
#short_format? ⇒ Boolean
Check if using short format (format 0)
179 180 181 |
# File 'lib/fontisan/tables/loca.rb', line 179 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).
144 145 146 147 148 149 150 |
# File 'lib/fontisan/tables/loca.rb', line 144 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 |