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 161 162 163 164 165 166
|
# frozen_string_literal: true
require 'spec_helper'
require 'ttfunk/table/cff'
RSpec.describe TTFunk::Table::Cff::Charset do
let(:font) { TTFunk::File.open(font_path) }
let(:charset) { font.cff.top_index[0].charset }
describe 'parsing and element access' do
context 'with an ID-based charset' do
let(:charset_id) { 0 } # iso_adobe
let(:charset) do
described_class.new(nil, TestFile.new(StringIO.new), charset_id, 0)
end
it 'includes all the entries from the expert charset' do
expect(charset.to_a).to eq(['.notdef'] + described_class.strings_for_charset_id(charset_id))
end
end
context 'with an array-formatted charset' do
let(:font_path) { test_font('Exo-Regular', :otf) }
it 'includes entries for all the glyphs in the font' do
# From the spec: There is one less element in the glyph name array than
# nGlyphs (i.e. charstrings count) because the .notdef glyph name is
# omitted.
expect(charset.items_count).to eq(font.cff.top_index[0].charstrings_index.items_count - 1)
end
it 'parses the entries correctly' do
strings = charset.to_a
# these should come from the set of "standard" strings
expect(strings[0..6]).to eq %w[.notdef uni000D space exclam quotedbl numbersign dollar]
# these should come from the strings index
expect(strings[-6..]).to eq(
%w[
endash.smcp emdash.smcp parenleft.alt parenright.alt
parenleft.smcp parenright.smcp
],
)
end
end
context 'with an 8-bit range-formatted charset' do
let(:font_path) { test_font('ComicJens-Regular', :otf) }
it 'includes entries for all the glyphs in the font' do
# From the spec: There is one less element in the glyph name array than
# nGlyphs (i.e. charstrings count) because the .notdef glyph name is
# omitted.
expect(charset.items_count).to eq(font.cff.top_index[0].charstrings_index.items_count - 1)
end
it 'parses the entries correctly' do
strings = charset.to_a
# these should come from the set of "standard" strings
expect(strings[0..6]).to eq %w[.notdef .null CR space exclam quotedbl numbersign]
# these should come from the strings index
expect(strings[-6..]).to eq %w[r_r s_s t_t w_w_w zero_seven zero_zero]
end
end
context 'with a 16-bit range-formatted charset' do
let(:font_path) { test_font('NotoSansCJKsc-Thin', :otf) }
it 'includes entries for all the glyphs in the font' do
# From the spec: There is one less element in the glyph name array than
# nGlyphs (i.e. charstrings count) because the .notdef glyph name is
# omitted.
expect(charset.items_count).to eq(font.cff.top_index[0].charstrings_index.items_count - 1)
end
it 'parses the entries correctly' do
strings = charset.to_a
# these should come from the set of "standard" strings
expect(strings[0..6]).to eq %w[.notdef space exclam quotedbl numbersign dollar percent]
# These should come from the strings index. This particular font is
# curious however in that most of the glyphs do not have a corresponding
# entry in the strings index even though the charset indicates they are
# all covered. This was probably done to cut down on file size since
# the font contains ~65k glyphs. Moreover, most of the glyphs in the
# font are Chinese characters which may not have useful descriptions.
# For example, the Unicode/CLDR data for most Chinese characters simply
# contains the description "CJK Ideograph."
expect(strings[-6..]).to eq [nil, nil, nil, nil, nil, nil]
end
end
end
describe '#encode' do
let(:font_path) { test_font('NotoSansCJKsc-Thin', :otf) }
let(:encoded) { charset.encode(charmap) }
context 'when the subset contains non-sequential SIDs' do
let(:charmap) do
# the idea here is to demonstrate that non-sequental SIDs can sometimes
# be more compactly represented as individual elements as opposed to
# ranges (supposed to be new => old glyph IDs)
{
0x20 => { old: 1, new: 1 },
0x23 => { old: 4, new: 4 },
0x29 => { old: 10, new: 10 },
0x2d => { old: 14, new: 14 },
0x2e => { old: 15, new: 15 },
0x34 => { old: 21, new: 21 },
}
end
it 'encodes using the array-based format' do
expect(encoded.bytes[0]).to eq(0)
end
it 'encodes correctly' do
# format (0x00), SIDs (2 bytes each)
expect(encoded.bytes).to eq(
[
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x0A,
0x00, 0x0E, 0x00, 0x0F, 0x00, 0x15,
],
)
end
end
context 'when the subset contains few sequential SIDs' do
let(:charmap) do
# i.e. the first 20 characters, in order
# (supposed to be new => old glyph IDs)
(1..20).to_h { |i| [0x20 + i, { old: i, new: i }] }
end
it 'encodes using the 8-bit range-based format' do
expect(encoded.bytes[0]).to eq(1)
end
it 'encodes correctly' do
# format (0x01), start SID (0x00, 0x01), rest (0x02, 0x13)
expect(encoded.bytes).to eq([0x01, 0x00, 0x01, 0x13])
end
end
context 'when the subset contains many sequential SIDs' do
let(:charmap) do
# we want to get a 2-byte range to demonstrate the 16-bit format
# (supposed to be new => old glyph IDs)
(1..(2**10)).to_h { |i| [0x20 + i, { old: i, new: i }] }
end
it 'encodes using the 16-bit range-based format' do
expect(encoded.bytes[0]).to eq(2)
end
it 'encodes correctly' do
# format (0x02), start SID (0x00, 0x01), rest (0x03, 0xFF)
expect(encoded.bytes).to eq([0x02, 0x00, 0x01, 0x03, 0xFF])
end
end
end
end
|