Class: TTFunk::Table::Cff::Encoding

Inherits:
SubTable
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ttfunk/table/cff/encoding.rb

Overview

CFF Encoding.

Constant Summary collapse

STANDARD_ENCODING_ID =

Predefined Standard Encoding ID.

0
EXPERT_ENCODING_ID =

Predefined Expert Encoding ID.

1
DEFAULT_ENCODING_ID =

Default encoding ID.

STANDARD_ENCODING_ID

Instance Attribute Summary collapse

Attributes inherited from SubTable

#file, #length, #table_offset

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SubTable

#eot?, #read

Constructor Details

#initialize(top_dict, file, offset = nil, length = nil) ⇒ Encoding #initialize(top_dict, file, charset_id) ⇒ Encoding

Returns a new instance of Encoding.

Overloads:

  • #initialize(top_dict, file, offset = nil, length = nil) ⇒ Encoding

    Parameters:

    • top_dict (TTFunk::Table:Cff::TopDict)
    • file (TTFunk::File)
    • offset (Integer) (defaults to: nil)
    • length (Integer) (defaults to: nil)
  • #initialize(top_dict, file, charset_id) ⇒ Encoding

    Parameters:

    • top_dict (TTFunk::Table:Cff::TopDict)
    • file (TTFunk::File)
    • encoding_id (Integer)

      0, 1, or 2



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ttfunk/table/cff/encoding.rb', line 59

def initialize(top_dict, file, offset_or_id = nil, length = nil)
  @top_dict = top_dict
  @offset_or_id = offset_or_id || DEFAULT_ENCODING_ID

  if offset
    super(file, offset, length)
    @supplemental = format >> 7 == 1
  else
    @items_count = self.class.codes_for_encoding_id(offset_or_id).size
    @supplemental = false
  end
end

Instance Attribute Details

#formatInteger (readonly)

Encodign format.

Returns:

  • (Integer)


40
41
42
# File 'lib/ttfunk/table/cff/encoding.rb', line 40

def format
  @format
end

#items_countInteger (readonly)

Number of encoded items.

Returns:

  • (Integer)


44
45
46
# File 'lib/ttfunk/table/cff/encoding.rb', line 44

def items_count
  @items_count
end

#offset_or_idInteger (readonly)

Offset or encoding ID.

Returns:

  • (Integer)


48
49
50
# File 'lib/ttfunk/table/cff/encoding.rb', line 48

def offset_or_id
  @offset_or_id
end

#top_dictTTFunk::Table::Cff::TopDict (readonly)

Top dict.



36
37
38
# File 'lib/ttfunk/table/cff/encoding.rb', line 36

def top_dict
  @top_dict
end

Class Method Details

.codes_for_encoding_id(encoding_id) ⇒ TTFunk::OneBasedArray<Integer>

Get predefined encoding by ID.

Parameters:

  • encoding_id (Integer)

Returns:



24
25
26
27
28
29
30
31
# File 'lib/ttfunk/table/cff/encoding.rb', line 24

def codes_for_encoding_id(encoding_id)
  case encoding_id
  when STANDARD_ENCODING_ID
    Encodings::STANDARD
  when EXPERT_ENCODING_ID
    Encodings::EXPERT
  end
end

Instance Method Details

#[](glyph_id) ⇒ Integer?

Get character code for glyph index.

Parameters:

  • glyph_id (Integer)

Returns:

  • (Integer, nil)


90
91
92
93
94
95
# File 'lib/ttfunk/table/cff/encoding.rb', line 90

def [](glyph_id)
  return 0 if glyph_id.zero?
  return code_for(glyph_id) if offset

  self.class.codes_for_encoding_id(offset_or_id)[glyph_id]
end

#each {|code| ... } ⇒ void #eachEnumerator

Iterate over character codes.

Overloads:

  • #each {|code| ... } ⇒ void

    This method returns an undefined value.

    Yield Parameters:

    • code (Integer)
  • #eachEnumerator

    Returns:

    • (Enumerator)


79
80
81
82
83
84
# File 'lib/ttfunk/table/cff/encoding.rb', line 79

def each
  return to_enum(__method__) unless block_given?

  # +1 adjusts for the implicit .notdef glyph
  (items_count + 1).times { |i| yield(self[i]) }
end

#encode(charmap) ⇒ String

Encode encoding.

Parameters:

  • charmap (Hash{Integer => Hash})

    keys are the charac codes, values are hashes:

    • ‘:old` (Integer) - glyph ID in the original font.

    • ‘:new` (Integer) - glyph ID in the subset font.

Returns:

  • (String)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/ttfunk/table/cff/encoding.rb', line 120

def encode(charmap)
  # Any subset encoding is all but guaranteed to be different from the
  # standard encoding so we don't even attempt to see if it matches. We
  # assume it's different and just encode it anew.

  return encode_supplemental(charmap) if supplemental?

  codes =
    charmap
      .reject { |_code, mapping| mapping[:new].zero? }
      .sort_by { |_code, mapping| mapping[:new] }
      .map { |(code, _m)| code }

  ranges = TTFunk::BinUtils.rangify(codes)

  # calculate whether storing the charset as a series of ranges is
  # more efficient (i.e. takes up less space) vs storing it as an
  # array of SID values
  total_range_size = (2 * ranges.size) +
    (element_width(:range_format) * ranges.size)

  total_array_size = codes.size * element_width(:array_format)

  if total_array_size <= total_range_size
    ([format_int(:array_format), codes.size] + codes).pack('C*')
  else
    element_fmt = element_format(:range_format)
    result = [format_int(:range_format), ranges.size].pack('CC')
    ranges.each { |range| result << range.pack(element_fmt) }
    result
  end
end

#offsetInteger?

Encoding offset in the file.

Returns:

  • (Integer, nil)


100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ttfunk/table/cff/encoding.rb', line 100

def offset
  # Numbers from 0..1 mean encoding IDs instead of offsets. IDs are
  # pre-defined, generic encodings that define the characters present
  # in the font.
  #
  # In the case of an offset, add the CFF table's offset since the
  # charset offset is relative to the start of the CFF table. Otherwise
  # return nil (no offset).
  if offset_or_id > 1
    offset_or_id + top_dict.cff_offset
  end
end

#supplemental?Boolean

Is this a supplemental encoding?

Returns:

  • (Boolean)


156
157
158
159
# File 'lib/ttfunk/table/cff/encoding.rb', line 156

def supplemental?
  # high-order bit set to 1 indicates supplemental encoding
  @supplemental
end