lib/ttfunk/table/cff/fd_selector.rb in ttfunk-1.7.0 vs lib/ttfunk/table/cff/fd_selector.rb in ttfunk-1.8.0

- old
+ new

@@ -1,26 +1,55 @@ # frozen_string_literal: true module TTFunk class Table class Cff < TTFunk::Table + # CFF FDSelect. class FdSelector < TTFunk::SubTable include Enumerable + # Array format. ARRAY_FORMAT = 0 + + # Range format. RANGE_FORMAT = 3 + # Range entry size. RANGE_ENTRY_SIZE = 3 + + # Array entry size. ARRAY_ENTRY_SIZE = 1 - attr_reader :top_dict, :count, :entries, :n_glyphs + # Top dict. + # @return [TTFunk::Table::Cff::TopDict] + attr_reader :top_dict + # Number of encoded items. + # @return [Integer] + attr_reader :items_count + + # Number of entries. + # @return [Array<Integer>] if format is array. + # @return [Array<Array(Range, Integer)>] if format is range. + attr_reader :entries + + # Number of glyphs. + # @return [Integer] + attr_reader :n_glyphs + + # @param top_dict [TTFunk::Table:Cff::TopDict] + # @param file [TTFunk::File] + # @param offset [Integer] + # @param length [Integer] def initialize(top_dict, file, offset, length = nil) @top_dict = top_dict super(file, offset, length) end + # Get font dict index for glyph ID. + # + # @return [Integer] def [](glyph_id) case format_sym when :array_format entries[glyph_id] @@ -28,38 +57,49 @@ if (entry = range_cache[glyph_id]) return entry end range, entry = - entries.bsearch do |rng, _| - if rng.cover?(glyph_id) - 0 - elsif glyph_id < rng.first - -1 - else - 1 - end - end + entries.bsearch { |rng, _| + if rng.cover?(glyph_id) + 0 + elsif glyph_id < rng.first + -1 + else + 1 + end + } range.each { |i| range_cache[i] = entry } entry end end + # Iterate over font dicts for each glyph ID. + # + # @yieldparam [Integer] font dict index. + # @return [void] def each return to_enum(__method__) unless block_given? - count.times { |i| yield self[i] } + items_count.times { |i| yield(self[i]) } end - # mapping is new -> old glyph ids - def encode(mapping) + # Encode Font dict selector. + # + # @param charmap [Hash{Integer => Hash}] keys are the charac codes, + # values are hashes: + # * `:old` (<tt>Integer</tt>) - glyph ID in the original font. + # * `:new` (<tt>Integer</tt>) - glyph ID in the subset font. + # @return [String] + def encode(charmap) # get list of [new_gid, fd_index] pairs new_indices = - mapping.keys.sort.map do |new_gid| - [new_gid, self[mapping[new_gid]]] - end + charmap + .reject { |code, mapping| mapping[:new].zero? && !code.zero? } + .sort_by { |_code, mapping| mapping[:new] } + .map { |(_code, mapping)| [mapping[:new], self[mapping[:old]]] } ranges = rangify_gids(new_indices) total_range_size = ranges.size * RANGE_ENTRY_SIZE total_array_size = new_indices.size * ARRAY_ENTRY_SIZE @@ -106,37 +146,37 @@ @format = read(1, 'C').first @length = 1 case format_sym when :array_format - @n_glyphs = top_dict.charstrings_index.count + @n_glyphs = top_dict.charstrings_index.items_count data = io.read(n_glyphs) @length += data.bytesize - @count = data.bytesize + @items_count = data.bytesize @entries = data.bytes when :range_format # +2 for sentinel GID, +2 for num_ranges num_ranges = read(2, 'n').first @length += (num_ranges * RANGE_ENTRY_SIZE) + 4 ranges = Array.new(num_ranges) { read(RANGE_ENTRY_SIZE, 'nC') } @entries = - ranges.each_cons(2).map do |first, second| + ranges.each_cons(2).map { |first, second| first_gid, fd_index = first second_gid, = second [(first_gid...second_gid), fd_index] - end + } # read the sentinel GID, otherwise known as the number of glyphs # in the font @n_glyphs = read(2, 'n').first last_start_gid, last_fd_index = ranges.last @entries << [(last_start_gid...(n_glyphs + 1)), last_fd_index] - @count = entries.reduce(0) { |sum, entry| sum + entry.first.size } + @items_count = entries.reduce(0) { |sum, entry| sum + entry.first.size } end end def format_sym case @format