File: hmtx.rb

package info (click to toggle)
ruby-ttfunk 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,472 kB
  • sloc: ruby: 7,954; makefile: 7
file content (87 lines) | stat: -rw-r--r-- 2,424 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# frozen_string_literal: true

require_relative '../table'

module TTFunk
  class Table
    # Horizontal Metrics (`hmtx`) table.
    class Hmtx < Table
      # Glyph horizontal metrics.
      # @return [Array<HorizontalMetric>]
      attr_reader :metrics

      # Left side bearings.
      # @return [Array<Ingteger>]
      attr_reader :left_side_bearings

      # Glyph widths.
      # @return [Array<Integer>]
      attr_reader :widths

      # Encode table.
      #
      # @param hmtx [TTFunk::Table::Hmtx]
      # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
      #   are old glyph IDs
      # @return [Hash{:number_of_metrics => Integer, :table => String}]
      #   * `:number_of_metrics` - number of mertrics is the table.
      #   * `:table` - encoded table.
      def self.encode(hmtx, mapping)
        metrics =
          mapping.keys.sort.map { |new_id|
            metric = hmtx.for(mapping[new_id])
            [metric.advance_width, metric.left_side_bearing]
          }

        {
          number_of_metrics: metrics.length,
          table: metrics.flatten.pack('n*'),
        }
      end

      # Horyzontal glyph metric.
      #
      # @!attribute [rw] advance_width
      #   @return [Integer] Advance width.
      # @!attribute [rw] left_side_bearing
      #   @return [Integer] Left side bearing.
      HorizontalMetric = Struct.new(:advance_width, :left_side_bearing)

      # Get horizontal metric for glyph.
      #
      # @param glyph_id [Integer]
      # @return [HorizontalMetric]
      def for(glyph_id)
        @metrics[glyph_id] ||
          metrics_cache[glyph_id] ||=
            HorizontalMetric.new(
              @metrics.last.advance_width,
              @left_side_bearings[glyph_id - @metrics.length],
            )
      end

      private

      def metrics_cache
        @metrics_cache ||= {}
      end

      def parse!
        @metrics = []

        file.horizontal_header.number_of_metrics.times do
          advance = read(2, 'n').first
          lsb = read_signed(1).first
          @metrics.push(HorizontalMetric.new(advance, lsb))
        end

        lsb_count = file.maximum_profile.num_glyphs -
          file.horizontal_header.number_of_metrics
        @left_side_bearings = read_signed(lsb_count)

        @widths = @metrics.map(&:advance_width)
        @widths += [@widths.last] * @left_side_bearings.length
      end
    end
  end
end