Class: Fontisan::Tables::Cff2::TableReader
- Inherits:
-
Object
- Object
- Fontisan::Tables::Cff2::TableReader
- Defined in:
- lib/fontisan/tables/cff2/table_reader.rb
Overview
Table reader for CFF2 with Variable Store support
CFF2TableReader parses CFF2 tables and extracts variation data from the Variable Store, which is essential for applying hints to variable fonts with CFF2 outlines.
Variable Store Structure:
- RegionList: Defines variation regions (min/peak/max per axis)
- ItemVariationData: Contains delta arrays per region
Reference: Adobe Technical Note #5177 (CFF2) Reference: OpenType spec - Item Variation Store
Constant Summary collapse
- VSTORE_OPERATOR =
CFF2-specific operators
24
Instance Attribute Summary collapse
-
#data ⇒ String
readonly
Binary CFF2 data.
-
#header ⇒ Hash
readonly
CFF2 header information.
-
#top_dict ⇒ Hash
readonly
Top DICT data.
-
#variable_store ⇒ Hash?
readonly
Variable Store data.
Instance Method Summary collapse
-
#initialize(data) ⇒ TableReader
constructor
Initialize reader with CFF2 data.
-
#read_charstrings(offset) ⇒ Cff::Index
Read CharStrings INDEX.
-
#read_header ⇒ Hash
Read CFF2 header.
-
#read_item_variation_data ⇒ Array<Hash>
Read Item Variation Data.
-
#read_private_dict(size, offset) ⇒ Hash
Read Private DICT with blend support.
-
#read_region ⇒ Hash
Read a single region.
-
#read_region_list ⇒ Array<Hash>
Read Region List from Variable Store.
-
#read_single_item_variation_data ⇒ Hash
Read a single Item Variation Data entry.
-
#read_top_dict ⇒ Hash
Read Top DICT.
-
#read_variable_store ⇒ Hash?
Read Variable Store from Top DICT.
Constructor Details
#initialize(data) ⇒ TableReader
Initialize reader with CFF2 data
45 46 47 48 49 50 51 52 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 45 def initialize(data) @data = data @io = StringIO.new(data) @io.set_encoding(Encoding::BINARY) @header = nil @top_dict = nil @variable_store = nil end |
Instance Attribute Details
#data ⇒ String (readonly)
Returns Binary CFF2 data.
28 29 30 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 28 def data @data end |
#header ⇒ Hash (readonly)
Returns CFF2 header information.
31 32 33 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 31 def header @header end |
#top_dict ⇒ Hash (readonly)
Returns Top DICT data.
34 35 36 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 34 def top_dict @top_dict end |
#variable_store ⇒ Hash? (readonly)
Returns Variable Store data.
37 38 39 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 37 def variable_store @variable_store end |
Instance Method Details
#read_charstrings(offset) ⇒ Cff::Index
Read CharStrings INDEX
233 234 235 236 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 233 def read_charstrings(offset) @io.seek(offset) Cff::Index.new(@io, start_offset: offset) end |
#read_header ⇒ Hash
Read CFF2 header
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 57 def read_header @io.rewind @header = { major_version: read_uint8, minor_version: read_uint8, header_size: read_uint8, top_dict_length: read_uint16, } # Validate CFF2 version unless @header[:major_version] == 2 && @header[:minor_version].zero? raise CorruptedTableError, "Invalid CFF2 version: #{@header[:major_version]}.#{@header[:minor_version]}" end @header end |
#read_item_variation_data ⇒ Array<Hash>
Read Item Variation Data
Contains delta arrays per region for varying values
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 154 def read_item_variation_data data_count = read_uint16 return [] if data_count.zero? item_variation_data = [] data_count.times do |_idx| item_data = read_single_item_variation_data item_variation_data << item_data rescue EOFError # break end item_variation_data end |
#read_private_dict(size, offset) ⇒ Hash
Read Private DICT with blend support
Private DICT in CFF2 can contain blend operators for variable hint parameters.
223 224 225 226 227 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 223 def read_private_dict(size, offset) @io.seek(offset) private_dict_data = @io.read(size) parse_dict(private_dict_data) end |
#read_region ⇒ Hash
Read a single region
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 134 def read_region axis_count = read_uint16 axes = [] axis_count.times do axes << { start_coord: read_f2dot14, peak_coord: read_f2dot14, end_coord: read_f2dot14, } end { axis_count: axis_count, axes: axes } end |
#read_region_list ⇒ Array<Hash>
Read Region List from Variable Store
Region List defines variation regions, where each region specifies min/peak/max values per axis.
119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 119 def read_region_list region_count = read_uint16 regions = [] region_count.times do region = read_region regions << region end regions end |
#read_single_item_variation_data ⇒ Hash
Read a single Item Variation Data entry
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 173 def read_single_item_variation_data item_count = read_uint16 short_delta_count = read_uint16 region_index_count = read_uint16 # Read region indices region_indices = [] region_index_count.times do region_indices << read_uint16 end # Read delta sets delta_sets = [] item_count.times do |_item_idx| deltas = [] # Short deltas (16-bit) short_delta_count.times do break if @io.eof? deltas << read_int16 end # Long deltas (8-bit) for remaining regions (region_index_count - short_delta_count).times do break if @io.eof? deltas << read_int8 end delta_sets << deltas rescue EOFError # break end { item_count: item_count, region_indices: region_indices, delta_sets: delta_sets, } end |
#read_top_dict ⇒ Hash
Read Top DICT
78 79 80 81 82 83 84 85 86 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 78 def read_top_dict read_header unless @header # Seek to Top DICT (after header) @io.seek(@header[:header_size]) top_dict_data = @io.read(@header[:top_dict_length]) @top_dict = parse_dict(top_dict_data) end |
#read_variable_store ⇒ Hash?
Read Variable Store from Top DICT
The Variable Store is referenced by the vstore operator (24) in the Top DICT. It contains regions and deltas for variation.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/fontisan/tables/cff2/table_reader.rb', line 94 def read_variable_store read_top_dict unless @top_dict # Check if Variable Store is present (operator 24) vstore_offset = @top_dict[VSTORE_OPERATOR] return nil unless vstore_offset # Seek to Variable Store @io.seek(vstore_offset) # Parse Variable Store structure @variable_store = { regions: read_region_list, item_variation_data: read_item_variation_data, } @variable_store end |