File: subset_spec.rb

package info (click to toggle)
ruby-ttfunk 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 18,472 kB
  • sloc: ruby: 7,954; makefile: 7
file content (160 lines) | stat: -rw-r--r-- 5,196 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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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
152
153
154
155
156
157
158
159
160
# frozen_string_literal: true

require 'spec_helper'
require 'stringio'
require 'ttfunk/subset'

describe 'subsetting' do # rubocop: disable RSpec/DescribeClass
  let(:space_char) { TTFunk::Subset::Unicode::SPACE_CHAR }

  it 'consistently names font for same subsets' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset1 = TTFunk::Subset.for(font, :unicode)
    subset1.use(97)
    name1 = TTFunk::File.new(subset1.encode).name.strings[6]

    subset2 = TTFunk::Subset.for(font, :unicode)
    subset2.use(97)
    name2 = TTFunk::File.new(subset2.encode).name.strings[6]

    expect(name1).to eq name2
  end

  it 'can reconstruct an entire font' do
    font = TTFunk::File.open(test_font('DejaVuSans'))
    subset = TTFunk::Subset.for(font, :unicode)

    font.cmap.unicode.first.code_map.each_key do |code_point|
      subset.use(code_point)
    end

    expect { subset.encode }.to_not raise_error
  end

  it 'always includes the space glyph' do
    font = TTFunk::File.open(test_font('DejaVuSans'))
    subset = TTFunk::Subset.for(font, :unicode)
    new_font = TTFunk::File.new(subset.encode)

    # space should be GID 1 since it's the only glyph in the font
    # (0 is always .notdef)
    expect(new_font.cmap.unicode.first[space_char]).to eq(1)
  end

  it "explodes if the space glyph isn't included" do
    font = TTFunk::File.open(test_font('DejaVuSans'))
    subset = TTFunk::Subset.for(font, :unicode)
    subset.instance_variable_get(:@subset).delete(space_char)
    expect { subset.encode }.to raise_error(/Space glyph .* must be included/)
  end

  it 'changes font names for different subsets' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset1 = TTFunk::Subset.for(font, :unicode)
    subset1.use(97)
    name1 = TTFunk::File.new(subset1.encode).name.strings[6]

    subset2 = TTFunk::Subset.for(font, :unicode)
    subset2.use(97)
    subset2.use(98)
    name2 = TTFunk::File.new(subset2.encode).name.strings[6]

    expect(name1).to_not eq name2
  end

  it 'calculates checksum correctly for empty table data' do
    font = TTFunk::File.open(test_font('Mplus1p'))
    subset1 = TTFunk::Subset.for(font, :unicode)
    expect { subset1.encode }.to_not raise_error
  end

  it 'generates font directory with tables in ascending order' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset = TTFunk::Subset.for(font, :unicode)
    subset.use(97)

    directory = TTFunk::File.new(subset.encode).directory
    table_tags = directory.tables.keys

    expect(table_tags.sort).to eq(table_tags)
    expect(table_tags.first).to be < table_tags.last
  end

  it 'calculates search_range, entry_selector & range_shift values' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset = TTFunk::Subset.for(font, :unicode)
    subset.use(97)
    subset_io = StringIO.new(subset.encode)

    scaler_type, table_count = subset_io.read(6).unpack('Nn')
    search_range, entry_selector, range_shift =
      subset_io.read(6).unpack('nnn')

    # Subset fonts include 14 tables by default.
    expected_table_count = 14
    # Smallest power of two less than number of tables, times 16.
    expected_search_range = 8 * 16
    # Log2 of max power of two smaller than number of tables.
    expected_entry_selector = 3
    # Range shift is defined as 16*table_count - search_range.
    expected_range_shift = (16 * expected_table_count) - expected_search_range

    expect(scaler_type).to eq(font.directory.scaler_type)
    expect(table_count).to eq(expected_table_count)
    expect(search_range).to eq(expected_search_range)
    expect(entry_selector).to eq(expected_entry_selector)
    expect(range_shift).to eq(expected_range_shift)
  end

  it 'knows which characters it includes' do
    font = TTFunk::File.open(test_font('DejaVuSans'))
    unicode = TTFunk::Subset.for(font, :unicode)
    unicode_8bit = TTFunk::Subset.for(font, :unicode_8bit)
    mac_roman = TTFunk::Subset.for(font, :mac_roman)
    windows1252 = TTFunk::Subset.for(font, :windows_1252) # rubocop: disable Naming/VariableNumber

    [unicode, unicode_8bit, mac_roman, windows1252].each do |subset|
      expect(subset).to_not be_includes(97)
      subset.use(97)
      expect(subset).to be_includes(97)
    end
  end

  it 'maps final code 0xFFFF to glyph 0 in generated type 4 cmap' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset = TTFunk::Subset.for(font, :unicode)
    subset.use(97)
    cmap = TTFunk::File.new(subset.encode).cmap

    # Unicode subsets only contain a single format 4 cmap subtable.
    expect(cmap.tables.size).to eq(1)
    format04 = cmap.tables.first
    expect(format04.format).to eq(4)
    expect(format04.code_map[0xFFFF]).to eq(0)
  end

  it 'sorts records in the name table correctly' do
    font = TTFunk::File.open(test_font('DejaVuSans'))

    subset = TTFunk::Subset.for(font, :unicode)
    subset.use(97)
    name = TTFunk::File.new(subset.encode).name

    records = []
    name.entries.each do |entry|
      records << [
        entry[:platform_id],
        entry[:encoding_id],
        entry[:language_id],
        entry[:name_id],
      ]
    end

    expect(records).to eq(records.sort)
  end
end