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

- old
+ new

@@ -1,123 +1,127 @@ # frozen_string_literal: true module TTFunk class Table class Cff < TTFunk::Table + # CFF top dict. class TopDict < TTFunk::Table::Cff::Dict + # Default charstring type. DEFAULT_CHARSTRING_TYPE = 2 + + # Length of placeholders for pointer operators. POINTER_PLACEHOLDER_LENGTH = 5 + + # Length of placeholders for other operators. PLACEHOLDER_LENGTH = 5 - # operators whose values are offsets that point to other parts - # of the file + # Operators whose values are offsets that point to other parts + # of the file. POINTER_OPERATORS = { charset: 15, encoding: 16, charstrings_index: 17, private: 18, font_index: 1236, - font_dict_selector: 1237 + font_dict_selector: 1237, }.freeze - # all the operators we currently care about + # All the operators we currently care about. OPERATORS = { **POINTER_OPERATORS, ros: 1230, - charstring_type: 1206 + charstring_type: 1206, }.freeze + # Inverse operator mapping. OPERATOR_CODES = OPERATORS.invert + # Encode dict. + # + # @return [TTFunk::EncodedString] def encode(*) EncodedString.new do |result| each_with_index do |(operator, operands), _idx| if operator == OPERATORS[:private] result << encode_private elsif pointer_operator?(operator) result << Placeholder.new( OPERATOR_CODES[operator], - length: POINTER_PLACEHOLDER_LENGTH + length: POINTER_PLACEHOLDER_LENGTH, ) else operands.each { |operand| result << encode_operand(operand) } end result << encode_operator(operator) end end end - def finalize(new_cff_data, new_to_old, old_to_new) + # Finalize the table. + # + # @param new_cff_data [TTFunk::EncodedString] + # @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 [void] + def finalize(new_cff_data, charmap) if charset - finalize_subtable( - new_cff_data, :charset, charset.encode(new_to_old) - ) + finalize_subtable(new_cff_data, :charset, charset.encode(charmap)) end if encoding - finalize_subtable( - new_cff_data, :encoding, encoding.encode(new_to_old, old_to_new) - ) + finalize_subtable(new_cff_data, :encoding, encoding.encode(charmap)) end if charstrings_index - finalize_subtable( - new_cff_data, - :charstrings_index, - charstrings_index.encode(new_to_old, &:encode) - ) + finalize_subtable(new_cff_data, :charstrings_index, charstrings_index.encode(charmap)) end if font_index - finalize_subtable( - new_cff_data, - :font_index, - font_index.encode do |font_dict| - font_dict.encode(new_to_old) - end - ) + finalize_subtable(new_cff_data, :font_index, font_index.encode) - font_index.finalize(new_cff_data, new_to_old) + font_index.finalize(new_cff_data) end if font_dict_selector - finalize_subtable( - new_cff_data, - :font_dict_selector, - font_dict_selector.encode(new_to_old) - ) + finalize_subtable(new_cff_data, :font_dict_selector, font_dict_selector.encode(charmap)) end if private_dict - encoded_private_dict = private_dict.encode(new_to_old) + encoded_private_dict = private_dict.encode encoded_offset = encode_integer32(new_cff_data.length) encoded_length = encode_integer32(encoded_private_dict.length) - new_cff_data.resolve_placeholder( - :"private_length_#{@table_offset}", encoded_length - ) + new_cff_data.resolve_placeholder(:"private_length_#{@table_offset}", encoded_length) + new_cff_data.resolve_placeholder(:"private_offset_#{@table_offset}", encoded_offset) - new_cff_data.resolve_placeholder( - :"private_offset_#{@table_offset}", encoded_offset - ) - private_dict.finalize(encoded_private_dict) new_cff_data << encoded_private_dict end end + # Registry Ordering Supplement. + # + # @return [Array(Integer, Integer, Integer), nil] def ros self[OPERATORS[:ros]] end + # Is Registry Ordering Supplement present in this dict? + # + # @return [Boolean] def ros? !ros.nil? end alias is_cid_font? ros? + # Charset specified in this dict. + # + # @return [TTFunk::Table::Cff::Charset, nil] def charset @charset ||= if (charset_offset_or_id = self[OPERATORS[:charset]]) if charset_offset_or_id.empty? Charset.new(self, file) @@ -125,86 +129,105 @@ Charset.new(self, file, charset_offset_or_id.first) end end end + # Encoding specified in this dict. + # + # @return [TTFunk::Table::Cff::Encoding, nil] def encoding + # PostScript type 1 fonts, i.e. CID fonts, i.e. some fonts that use + # the CFF table, don't specify an encoding, so this can be nil @encoding ||= - begin - # PostScript type 1 fonts, i.e. CID fonts, i.e. some fonts that use - # the CFF table, don't specify an encoding, so this can be nil - if (encoding_offset_or_id = self[OPERATORS[:encoding]]) - Encoding.new(self, file, encoding_offset_or_id.first) - end + if (encoding_offset_or_id = self[OPERATORS[:encoding]]) + Encoding.new(self, file, encoding_offset_or_id.first) end end - # https://www.microsoft.com/typography/otspec/cff.htm + # Charstrings index specified in this dict. # - # "OpenType fonts with TrueType outlines use a glyph index to specify - # and access glyphs within a font; e.g., to index within the 'loca' - # table and thereby access glyph data in the 'glyf' table. This concept - # is retained in OpenType CFF fonts, except that glyph data is accessed - # through the CharStrings INDEX of the CFF table." + # > OpenType fonts with TrueType outlines use a glyph index to specify + # and access glyphs within a font; e.g., to index within the `loca` + # table and thereby access glyph data in the `glyf` table. This + # concept is retained in OpenType CFF fonts, except that glyph data is + # accessed through the CharStrings INDEX of the CFF table. + # + # > --- [CFF — Compact Font Format Table](https://www.microsoft.com/typography/otspec/cff.htm) + # + # @return [TTFunk::Table::Cff::CharstringsIndex, nil] def charstrings_index @charstrings_index ||= if (charstrings_offset = self[OPERATORS[:charstrings_index]]) - CharstringsIndex.new( - self, file, cff_offset + charstrings_offset.first - ) + CharstringsIndex.new(self, file, cff_offset + charstrings_offset.first) end end + # Charstring type specified in this dict. + # + # @return [Integer] def charstring_type @charstring_type = self[OPERATORS[:charstring_type]] || DEFAULT_CHARSTRING_TYPE end + # Font index specified in this dict. + # + # @return [TTFunk::Table::Cff::FontIndex, nil] def font_index @font_index ||= if (font_index_offset = self[OPERATORS[:font_index]]) FontIndex.new(self, file, cff_offset + font_index_offset.first) end end + # Font dict selector specified in this dict. + # + # @return [TTFunk::Table::Cff::FdSelector, nil] def font_dict_selector @font_dict_selector ||= if (fd_select_offset = self[OPERATORS[:font_dict_selector]]) FdSelector.new(self, file, cff_offset + fd_select_offset.first) end end + # Private dict specified in this dict. + # + # @return [TTFunk::Table::Cff::PrivateDict, nil] def private_dict @private_dict ||= if (info = self[OPERATORS[:private]]) private_dict_length, private_dict_offset = info - PrivateDict.new( - file, cff_offset + private_dict_offset, private_dict_length - ) + PrivateDict.new(file, cff_offset + private_dict_offset, private_dict_length) end end + # CFF table in this file. + # + # @return [TTFunk::Table::Cff] def cff file.cff end + # Ofsset of CFF table in the file. + # + # @return [Integer] def cff_offset cff.offset end private def encode_private EncodedString.new do |result| result << Placeholder.new( :"private_length_#{@table_offset}", - length: PLACEHOLDER_LENGTH + length: PLACEHOLDER_LENGTH, ) result << Placeholder.new( :"private_offset_#{@table_offset}", - length: PLACEHOLDER_LENGTH + length: PLACEHOLDER_LENGTH, ) end end def finalize_subtable(new_cff_data, name, table_data)