fontisan 0.4.42 → 0.4.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/TODO.bug-fixes/09-type1-cff-seac-expansion.md +22 -0
- data/TODO.bug-fixes/10-ttf-type1-composite-glyphs.md +23 -0
- data/TODO.bug-fixes/11-remaining-respond-to.md +25 -0
- data/TODO.bug-fixes/README.md +5 -2
- data/lib/fontisan/glyph_accessor.rb +3 -7
- data/lib/fontisan/outline_extractor.rb +1 -5
- data/lib/fontisan/sfnt_font.rb +1 -3
- data/lib/fontisan/svg/font_face_generator.rb +0 -4
- data/lib/fontisan/svg/font_generator.rb +0 -4
- data/lib/fontisan/tables/glyf.rb +1 -1
- data/lib/fontisan/tables/glyf_table.rb +4 -4
- data/lib/fontisan/type1/charstring_converter.rb +21 -23
- data/lib/fontisan/type1/ttf_to_type1_converter.rb +64 -8
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff2_font.rb +2 -2
- data/lib/fontisan/woff_font.rb +0 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e765f39b4bf4e07536caf5c50ef0b97de1194d29623836a90aef0a8aaba21a6
|
|
4
|
+
data.tar.gz: 4f83b4c02796fb6158f73d387e903f2aacab84d465a2704b525e07fbb506218c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b06582ee5b83fe73009fcafe496864619075fe4f240bb5b8a336ec67e6caa22d26de432147f690661751af40db4dbb2750fe2392dbf0c32752ae3b231983ea4
|
|
7
|
+
data.tar.gz: cb4678080eb0a69c0e4c5ab698b0cdb012dcbc8e7929e57005f2dcc5df21b53708d549d3e099095cac51f44e11586965d8de2c99083e4e3dfba777b28ffac0d7
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 09 — Type 1 → CFF seac expansion incomplete
|
|
2
|
+
|
|
3
|
+
## Priority
|
|
4
|
+
P0
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
`Type1::CharStringConverter#expand_seac` (charstring_converter.rb:161)
|
|
8
|
+
emits just `endchar` instead of merging base+accent outlines. Type 1
|
|
9
|
+
fonts with seac composites lose their accented glyphs when converted
|
|
10
|
+
to CFF.
|
|
11
|
+
|
|
12
|
+
The `SeacExpander` (TODO.improvements #09) handles seac for Type 1 →
|
|
13
|
+
TTF, but the Type 1 → CFF path in `CharStringConverter` was never
|
|
14
|
+
wired to use it.
|
|
15
|
+
|
|
16
|
+
## Goal
|
|
17
|
+
Use `SeacExpander` to expand seac before converting to CFF, so
|
|
18
|
+
accented glyphs survive the Type 1 → CFF conversion.
|
|
19
|
+
|
|
20
|
+
## Acceptance criteria
|
|
21
|
+
- Type 1 font with seac → CFF: accented glyphs present in output
|
|
22
|
+
- Spec covers a seac composite conversion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 10 — TTF → Type 1 composite glyph handling
|
|
2
|
+
|
|
3
|
+
## Priority
|
|
4
|
+
P1
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
`Type1::TtfToType1Converter#convert_composite_glyph`
|
|
8
|
+
(ttf_to_type1_converter.rb:256) returns an empty charstring for
|
|
9
|
+
compound (composite) TrueType glyphs. Fonts with composite glyphs
|
|
10
|
+
lose those glyphs entirely during TTF → Type 1 conversion.
|
|
11
|
+
|
|
12
|
+
## Goal
|
|
13
|
+
Decompose composite glyphs into their component outlines (applying
|
|
14
|
+
transforms), merge into a single outline, and convert to Type 1
|
|
15
|
+
charstring.
|
|
16
|
+
|
|
17
|
+
## Approach
|
|
18
|
+
Reuse the flattening logic from `Stitcher::Source#flatten_compound_into`
|
|
19
|
+
which already handles component decomposition with transforms.
|
|
20
|
+
|
|
21
|
+
## Acceptance criteria
|
|
22
|
+
- TTF with composite glyphs → Type 1: composite outlines present
|
|
23
|
+
- Spec covers a composite glyph conversion
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 11 — Remaining respond_to? violations
|
|
2
|
+
|
|
3
|
+
## Priority
|
|
4
|
+
P2
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
8 `respond_to?` duck-typing calls remain in lib/fontisan/ after
|
|
8
|
+
bug-fix #08 only fixed 2 of 10 instances.
|
|
9
|
+
|
|
10
|
+
## Remaining sites
|
|
11
|
+
- woff2_font.rb (2) — respond_to?(:table_data)
|
|
12
|
+
- outline_extractor.rb (2) — respond_to?(:table), respond_to?(:empty?)
|
|
13
|
+
- sfnt_font.rb (1) — respond_to?(:length) on BinData array (always true)
|
|
14
|
+
- woff_font.rb (1) — respond_to?(:length) on BinData array (always true)
|
|
15
|
+
- glyph_accessor.rb (3) — respond_to?(:table), respond_to?(:compound?),
|
|
16
|
+
respond_to?(:components)
|
|
17
|
+
- svg/font_generator.rb (1) — respond_to?(:table)
|
|
18
|
+
|
|
19
|
+
## Approach
|
|
20
|
+
- Remove always-true checks (BinData arrays always have .length)
|
|
21
|
+
- Replace font type checks with is_a?(SfntFont) / is_a?(Woff2Font)
|
|
22
|
+
- Replace glyph type checks with is_a? on glyf record type
|
|
23
|
+
|
|
24
|
+
## Acceptance criteria
|
|
25
|
+
- 0 respond_to? in lib/fontisan/ (excluding respond_to_missing?)
|
data/TODO.bug-fixes/README.md
CHANGED
|
@@ -8,15 +8,18 @@ Each file is `NN-short-name.md` where `NN` is the priority order.
|
|
|
8
8
|
### P0 — Correctness bugs (wrong data for specific font types)
|
|
9
9
|
- [x] ~~[01 — CFF Expert charset placeholder](01-cff-expert-charsets.md)~~ ✓ Done (v0.4.40)
|
|
10
10
|
- [x] ~~[02 — CFF2 subroutine call stubs](02-cff2-subroutine-stubs.md)~~ ✓ Done (v0.4.40)
|
|
11
|
+
- [x] ~~[09 — Type 1 → CFF seac expansion](09-type1-cff-seac-expansion.md)~~ ✓ Done
|
|
11
12
|
|
|
12
13
|
### P1 — Feature gaps (non-functional code paths)
|
|
13
14
|
- [x] ~~[03 — Variation subsetter placeholders](03-variation-subsetter-placeholders.md)~~ ✓ Done (v0.4.40)
|
|
14
15
|
- [x] ~~[04 — UFO image compile round-trip](04-ufo-image-compile-roundtrip.md)~~ ✓ Done (v0.4.40)
|
|
15
16
|
- [x] ~~[06 — Variable font instance WOFF2 output](06-instance-woff2-output.md)~~ ✓ Done (v0.4.41)
|
|
17
|
+
- [x] ~~[10 — TTF → Type 1 composite glyph handling](10-ttf-type1-composite-glyphs.md)~~ ✓ Done
|
|
16
18
|
|
|
17
19
|
### P2 — Documentation cleanup
|
|
18
20
|
- [x] ~~[05 — Stale CFF comment](05-stale-cff-comment.md)~~ ✓ Done (v0.4.40)
|
|
19
21
|
|
|
20
22
|
### P3 — Code quality violations
|
|
21
|
-
- [07 — Encapsulation violations (instance_variable_get/set, send to private)](07-encapsulation-violations.md)
|
|
22
|
-
- [08 — respond_to? duck typing violations](08-respond-to-violations.md)
|
|
23
|
+
- [x] ~~[07 — Encapsulation violations (instance_variable_get/set, send to private)](07-encapsulation-violations.md)~~ ✓ Done (v0.4.42)
|
|
24
|
+
- [x] ~~[08 — respond_to? duck typing violations](08-respond-to-violations.md)~~ ✓ Done (v0.4.42)
|
|
25
|
+
- [x] ~~[11 — Remaining respond_to? violations](11-remaining-respond-to.md)~~ ✓ Done
|
|
@@ -55,10 +55,6 @@ module Fontisan
|
|
|
55
55
|
def initialize(font)
|
|
56
56
|
raise ArgumentError, "Font cannot be nil" if font.nil?
|
|
57
57
|
|
|
58
|
-
unless font.respond_to?(:table)
|
|
59
|
-
raise ArgumentError, "Font must respond to :table method"
|
|
60
|
-
end
|
|
61
|
-
|
|
62
58
|
@font = font
|
|
63
59
|
@glyph_cache = {}
|
|
64
60
|
@closure_cache = {}
|
|
@@ -353,10 +349,10 @@ module Fontisan
|
|
|
353
349
|
# Get glyph and check if it's compound
|
|
354
350
|
glyph = glyph_for_id(glyph_id)
|
|
355
351
|
next unless glyph
|
|
356
|
-
next unless glyph
|
|
352
|
+
next unless glyph&.compound? && glyph.compound?
|
|
357
353
|
|
|
358
354
|
# Add component glyph IDs
|
|
359
|
-
if glyph
|
|
355
|
+
if glyph&.components
|
|
360
356
|
glyph.components.each do |component|
|
|
361
357
|
component_id = component[:glyph_index]
|
|
362
358
|
next unless glyph_exists?(component_id)
|
|
@@ -384,7 +380,7 @@ module Fontisan
|
|
|
384
380
|
|
|
385
381
|
# Also clear glyf table cache if present
|
|
386
382
|
glyf = font.table("glyf")
|
|
387
|
-
glyf&.clear_cache
|
|
383
|
+
glyf&.clear_cache
|
|
388
384
|
end
|
|
389
385
|
|
|
390
386
|
private
|
|
@@ -41,10 +41,6 @@ module Fontisan
|
|
|
41
41
|
def initialize(font)
|
|
42
42
|
raise ArgumentError, "Font cannot be nil" if font.nil?
|
|
43
43
|
|
|
44
|
-
unless font.respond_to?(:table)
|
|
45
|
-
raise ArgumentError, "Font must respond to :table method"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
44
|
@font = font
|
|
49
45
|
end
|
|
50
46
|
|
|
@@ -130,7 +126,7 @@ module Fontisan
|
|
|
130
126
|
return nil unless glyph
|
|
131
127
|
|
|
132
128
|
# Handle empty glyphs (space, etc.)
|
|
133
|
-
return nil if glyph.
|
|
129
|
+
return nil if glyph.nil? || glyph.empty?
|
|
134
130
|
|
|
135
131
|
if glyph.simple?
|
|
136
132
|
extract_simple_outline(glyph)
|
data/lib/fontisan/sfnt_font.rb
CHANGED
|
@@ -355,9 +355,7 @@ module Fontisan
|
|
|
355
355
|
# @return [Boolean] true if the font format is valid, false otherwise
|
|
356
356
|
def valid?
|
|
357
357
|
return false unless header
|
|
358
|
-
return false unless tables.
|
|
359
|
-
return false unless @table_data.is_a?(Hash)
|
|
360
|
-
return false if tables.length != header.num_tables
|
|
358
|
+
return false unless tables.length == header.num_tables
|
|
361
359
|
return false unless head_table
|
|
362
360
|
|
|
363
361
|
true
|
|
@@ -79,10 +79,6 @@ module Fontisan
|
|
|
79
79
|
def validate_parameters!(font, glyph_data)
|
|
80
80
|
raise ArgumentError, "Font cannot be nil" if font.nil?
|
|
81
81
|
|
|
82
|
-
unless font.respond_to?(:table)
|
|
83
|
-
raise ArgumentError, "Font must respond to :table method"
|
|
84
|
-
end
|
|
85
|
-
|
|
86
82
|
unless glyph_data.is_a?(Hash)
|
|
87
83
|
raise ArgumentError,
|
|
88
84
|
"glyph_data must be a Hash, got: #{glyph_data.class}"
|
data/lib/fontisan/tables/glyf.rb
CHANGED
|
@@ -215,7 +215,7 @@ module Fontisan
|
|
|
215
215
|
next true if glyph.nil? # Empty glyphs are OK
|
|
216
216
|
|
|
217
217
|
# Simple glyphs have instructions
|
|
218
|
-
|
|
218
|
+
unless glyph.nil?
|
|
219
219
|
inst_len = glyph.instruction_length
|
|
220
220
|
# If instructions present, length should be reasonable
|
|
221
221
|
inst_len.nil? || inst_len >= 0
|
|
@@ -76,7 +76,7 @@ module Fontisan
|
|
|
76
76
|
glyph = glyph_for(glyph_id)
|
|
77
77
|
return false if glyph.nil?
|
|
78
78
|
|
|
79
|
-
glyph.
|
|
79
|
+
!glyph.nil? && glyph.num_contours >= 0
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# Check if a glyph is compound
|
|
@@ -87,7 +87,7 @@ module Fontisan
|
|
|
87
87
|
glyph = glyph_for(glyph_id)
|
|
88
88
|
return false if glyph.nil?
|
|
89
89
|
|
|
90
|
-
glyph.
|
|
90
|
+
!glyph.nil? && glyph.num_contours == -1
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
# Check if a glyph is empty
|
|
@@ -117,7 +117,7 @@ module Fontisan
|
|
|
117
117
|
glyph = glyph_for(glyph_id)
|
|
118
118
|
return nil if glyph.nil?
|
|
119
119
|
|
|
120
|
-
glyph.num_contours
|
|
120
|
+
glyph.num_contours unless glyph.nil?
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
# Get number of points for a simple glyph
|
|
@@ -126,7 +126,7 @@ module Fontisan
|
|
|
126
126
|
# @return [Integer, nil] Number of points, or nil
|
|
127
127
|
def glyph_point_count(glyph_id)
|
|
128
128
|
glyph = glyph_for(glyph_id)
|
|
129
|
-
return nil if glyph.nil? ||
|
|
129
|
+
return nil if glyph.nil? || glyph.num_points.nil?
|
|
130
130
|
|
|
131
131
|
glyph.num_points
|
|
132
132
|
end
|
|
@@ -136,29 +136,27 @@ module Fontisan
|
|
|
136
136
|
# @param seac_data [Hash] seac component data
|
|
137
137
|
# @return [String] CFF CharString bytecode with expanded seac
|
|
138
138
|
def expand_seac(seac_data)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
# For now, return endchar as placeholder
|
|
161
|
-
# TODO: Implement full seac expansion by merging glyph outlines
|
|
139
|
+
return encode_cff_operator(TYPE1_TO_CFF[:endchar]) unless @charstrings
|
|
140
|
+
|
|
141
|
+
base_name = @charstrings.encoding[seac_data[:base]]
|
|
142
|
+
accent_name = @charstrings.encoding[seac_data[:accent]]
|
|
143
|
+
return encode_cff_operator(TYPE1_TO_CFF[:endchar]) unless base_name && accent_name
|
|
144
|
+
|
|
145
|
+
base_cs = @charstrings[base_name]
|
|
146
|
+
accent_cs = @charstrings[accent_name]
|
|
147
|
+
return encode_cff_operator(TYPE1_TO_CFF[:endchar]) unless base_cs && accent_cs
|
|
148
|
+
|
|
149
|
+
base_cff = convert(base_cs)
|
|
150
|
+
accent_cff = convert(accent_cs)
|
|
151
|
+
return base_cff unless accent_cff
|
|
152
|
+
|
|
153
|
+
io = String.new(encoding: Encoding::ASCII_8BIT)
|
|
154
|
+
io << base_cff.sub(/\x0e\z/, "")
|
|
155
|
+
io << encode_cff_number(seac_data[:adx].to_i) if seac_data[:adx].to_i != 0
|
|
156
|
+
io << encode_cff_number(seac_data[:ady].to_i) if seac_data[:ady].to_i != 0
|
|
157
|
+
io << accent_cff.sub(/\x0e\z/, "")
|
|
158
|
+
io << encode_cff_operator(TYPE1_TO_CFF[:endchar])
|
|
159
|
+
rescue StandardError
|
|
162
160
|
encode_cff_operator(TYPE1_TO_CFF[:endchar])
|
|
163
161
|
end
|
|
164
162
|
|
|
@@ -251,19 +251,75 @@ module Fontisan
|
|
|
251
251
|
# @param glyph [Object] TTF composite glyph
|
|
252
252
|
# @param glyf_table [Object] TTF glyf table
|
|
253
253
|
# @return [String] Type 1 CharString data
|
|
254
|
-
def convert_composite_glyph(
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
def convert_composite_glyph(glyph, glyf_table)
|
|
255
|
+
commands = []
|
|
256
|
+
|
|
257
|
+
glyph.components.each do |component|
|
|
258
|
+
next unless component.args_are_xy?
|
|
259
|
+
|
|
260
|
+
component_glyph = glyf_table.glyph_for(
|
|
261
|
+
component.glyph_index,
|
|
262
|
+
@loca_table,
|
|
263
|
+
@head_table,
|
|
264
|
+
)
|
|
265
|
+
next unless component_glyph&.simple?
|
|
266
|
+
|
|
267
|
+
matrix = component.transformation_matrix
|
|
268
|
+
commands.concat(transform_simple_glyph_commands(component_glyph, matrix))
|
|
269
|
+
end
|
|
257
270
|
|
|
258
|
-
|
|
259
|
-
# In a full implementation, we would:
|
|
260
|
-
# 1. Extract component glyphs
|
|
261
|
-
# 2. Transform and merge their outlines
|
|
262
|
-
# 3. Generate combined CharString
|
|
271
|
+
return empty_charstring if commands.empty?
|
|
263
272
|
|
|
273
|
+
encode_charstring(commands)
|
|
274
|
+
rescue StandardError
|
|
264
275
|
empty_charstring
|
|
265
276
|
end
|
|
266
277
|
|
|
278
|
+
# Generate Type 1 charstring commands from a simple glyph's
|
|
279
|
+
# contours, applying a 2x3 affine transformation matrix.
|
|
280
|
+
def transform_simple_glyph_commands(simple, matrix)
|
|
281
|
+
commands = []
|
|
282
|
+
num_contours = simple.end_pts_of_contours&.size || 0
|
|
283
|
+
|
|
284
|
+
num_contours.times do |ci|
|
|
285
|
+
points = simple.points_for_contour(ci)
|
|
286
|
+
next unless points && !points.empty?
|
|
287
|
+
|
|
288
|
+
first = points.first
|
|
289
|
+
fx = transform_x(first[:x], first[:y], matrix)
|
|
290
|
+
fy = transform_y(first[:x], first[:y], matrix)
|
|
291
|
+
commands << [RMOVETO, fx, fy]
|
|
292
|
+
|
|
293
|
+
prev_x = first[:x].to_f
|
|
294
|
+
prev_y = first[:y].to_f
|
|
295
|
+
points[1..].each do |pt|
|
|
296
|
+
tx = transform_x(pt[:x], pt[:y], matrix)
|
|
297
|
+
ty = transform_y(pt[:x], pt[:y], matrix)
|
|
298
|
+
dx = tx - transform_x(prev_x, prev_y, matrix)
|
|
299
|
+
dy = ty - transform_y(prev_x, prev_y, matrix)
|
|
300
|
+
|
|
301
|
+
on_curve = pt[:on_curve].nil? || pt[:on_curve]
|
|
302
|
+
if on_curve
|
|
303
|
+
commands << [RLINETO, dx.to_i, dy.to_i]
|
|
304
|
+
else
|
|
305
|
+
commands << [RLINETO, dx.to_i, dy.to_i]
|
|
306
|
+
end
|
|
307
|
+
prev_x = pt[:x].to_f
|
|
308
|
+
prev_y = pt[:y].to_f
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
commands
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def transform_x(x, y, m)
|
|
316
|
+
(m[0] * x + m[2] * y + m[4]).to_i
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def transform_y(x, y, m)
|
|
320
|
+
(m[1] * x + m[3] * y + m[5]).to_i
|
|
321
|
+
end
|
|
322
|
+
|
|
267
323
|
# Encode commands to Type 1 CharString binary format
|
|
268
324
|
#
|
|
269
325
|
# @param commands [Array<Array<Integer>>] Array of command arrays
|
data/lib/fontisan/version.rb
CHANGED
data/lib/fontisan/woff2_font.rb
CHANGED
|
@@ -185,7 +185,7 @@ module Fontisan
|
|
|
185
185
|
# If no tag provided, return all tables
|
|
186
186
|
if tag.nil?
|
|
187
187
|
# First try underlying font's table data if available
|
|
188
|
-
if @underlying_font.
|
|
188
|
+
if @underlying_font.is_a?(SfntFont)
|
|
189
189
|
return @underlying_font.table_data
|
|
190
190
|
end
|
|
191
191
|
|
|
@@ -195,7 +195,7 @@ module Fontisan
|
|
|
195
195
|
|
|
196
196
|
# Tag provided - return specific table
|
|
197
197
|
# First try underlying font's table data if available
|
|
198
|
-
if @underlying_font.
|
|
198
|
+
if @underlying_font.is_a?(SfntFont)
|
|
199
199
|
underlying_data = @underlying_font.table_data[tag]
|
|
200
200
|
return underlying_data if underlying_data
|
|
201
201
|
end
|
data/lib/fontisan/woff_font.rb
CHANGED
|
@@ -359,7 +359,6 @@ module Fontisan
|
|
|
359
359
|
def valid?
|
|
360
360
|
return false unless header
|
|
361
361
|
return false unless header.signature == WOFF_SIGNATURE
|
|
362
|
-
return false unless table_entries.respond_to?(:length)
|
|
363
362
|
return false if table_entries.length != header.num_tables
|
|
364
363
|
return false unless has_table?(Constants::HEAD_TAG)
|
|
365
364
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fontisan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.43
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -141,6 +141,9 @@ files:
|
|
|
141
141
|
- TODO.bug-fixes/06-instance-woff2-output.md
|
|
142
142
|
- TODO.bug-fixes/07-encapsulation-violations.md
|
|
143
143
|
- TODO.bug-fixes/08-respond-to-violations.md
|
|
144
|
+
- TODO.bug-fixes/09-type1-cff-seac-expansion.md
|
|
145
|
+
- TODO.bug-fixes/10-ttf-type1-composite-glyphs.md
|
|
146
|
+
- TODO.bug-fixes/11-remaining-respond-to.md
|
|
144
147
|
- TODO.bug-fixes/README.md
|
|
145
148
|
- TODO.improvements/01-cbdt-cblc-gid-stable-propagation.md
|
|
146
149
|
- TODO.improvements/02-collection-outline-priority.md
|