fontisan 0.2.22 → 0.3.0
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/.rubocop.yml +6 -0
- data/.rubocop_todo.yml +93 -17
- data/CHANGELOG.md +12 -2
- data/README.adoc +6 -210
- data/fontisan.gemspec +48 -0
- data/lib/fontisan/cldr/unicode_set_parser.rb +23 -6
- data/lib/fontisan/cldr/version_resolver.rb +1 -1
- data/lib/fontisan/cli.rb +4 -168
- data/lib/fontisan/commands.rb +0 -3
- data/lib/fontisan/formatters/text_formatter.rb +0 -6
- data/lib/fontisan/formatters.rb +0 -3
- data/lib/fontisan/hints.rb +6 -3
- data/lib/fontisan/models.rb +4 -4
- data/lib/fontisan/pipeline/strategies.rb +4 -2
- data/lib/fontisan/pipeline.rb +2 -1
- data/lib/fontisan/stitcher/selector/codepoints.rb +29 -0
- data/lib/fontisan/stitcher/selector/gid.rb +25 -0
- data/lib/fontisan/stitcher/selector/range.rb +30 -0
- data/lib/fontisan/stitcher/selector.rb +26 -0
- data/lib/fontisan/stitcher/source.rb +97 -0
- data/lib/fontisan/stitcher.rb +182 -0
- data/lib/fontisan/stitcher_cli.rb +69 -0
- data/lib/fontisan/tables/cff.rb +2 -1
- data/lib/fontisan/tables.rb +2 -1
- data/lib/fontisan/ufo/anchor.rb +17 -0
- data/lib/fontisan/ufo/cli.rb +85 -0
- data/lib/fontisan/ufo/compile/base_compiler.rb +81 -0
- data/lib/fontisan/ufo/compile/cff.rb +224 -0
- data/lib/fontisan/ufo/compile/cmap.rb +129 -0
- data/lib/fontisan/ufo/compile/filters/cubic_to_quadratic.rb +174 -0
- data/lib/fontisan/ufo/compile/filters/decompose_components.rb +33 -0
- data/lib/fontisan/ufo/compile/filters/flatten_components.rb +22 -0
- data/lib/fontisan/ufo/compile/filters/reverse_contour_direction.rb +27 -0
- data/lib/fontisan/ufo/compile/filters.rb +57 -0
- data/lib/fontisan/ufo/compile/glyf_loca.rb +145 -0
- data/lib/fontisan/ufo/compile/head.rb +98 -0
- data/lib/fontisan/ufo/compile/hhea.rb +36 -0
- data/lib/fontisan/ufo/compile/hmtx.rb +27 -0
- data/lib/fontisan/ufo/compile/maxp.rb +57 -0
- data/lib/fontisan/ufo/compile/name.rb +79 -0
- data/lib/fontisan/ufo/compile/os2.rb +81 -0
- data/lib/fontisan/ufo/compile/otf_compiler.rb +43 -0
- data/lib/fontisan/ufo/compile/post.rb +32 -0
- data/lib/fontisan/ufo/compile/ttf_compiler.rb +69 -0
- data/lib/fontisan/ufo/compile.rb +48 -0
- data/lib/fontisan/ufo/component.rb +18 -0
- data/lib/fontisan/ufo/contour.rb +29 -0
- data/lib/fontisan/ufo/convert/from_bin_data.rb +246 -0
- data/lib/fontisan/ufo/convert.rb +18 -0
- data/lib/fontisan/ufo/data_set.rb +21 -0
- data/lib/fontisan/ufo/features.rb +17 -0
- data/lib/fontisan/ufo/font.rb +61 -0
- data/lib/fontisan/ufo/glyph.rb +421 -0
- data/lib/fontisan/ufo/guideline.rb +19 -0
- data/lib/fontisan/ufo/image.rb +16 -0
- data/lib/fontisan/ufo/image_set.rb +19 -0
- data/lib/fontisan/ufo/info.rb +79 -0
- data/lib/fontisan/ufo/kerning.rb +32 -0
- data/lib/fontisan/ufo/layer.rb +38 -0
- data/lib/fontisan/ufo/layer_set.rb +37 -0
- data/lib/fontisan/ufo/lib.rb +24 -0
- data/lib/fontisan/ufo/plist.rb +118 -0
- data/lib/fontisan/ufo/point.rb +38 -0
- data/lib/fontisan/ufo/reader.rb +144 -0
- data/lib/fontisan/ufo/transformation.rb +39 -0
- data/lib/fontisan/ufo/writer.rb +115 -0
- data/lib/fontisan/ufo.rb +44 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan.rb +3 -3
- metadata +57 -70
- data/lib/fontisan/audit/codepoint_range_coalescer.rb +0 -41
- data/lib/fontisan/audit/context.rb +0 -122
- data/lib/fontisan/audit/differ.rb +0 -124
- data/lib/fontisan/audit/extractors/aggregations.rb +0 -54
- data/lib/fontisan/audit/extractors/base.rb +0 -26
- data/lib/fontisan/audit/extractors/color_capabilities.rb +0 -141
- data/lib/fontisan/audit/extractors/coverage.rb +0 -48
- data/lib/fontisan/audit/extractors/hinting.rb +0 -197
- data/lib/fontisan/audit/extractors/identity.rb +0 -52
- data/lib/fontisan/audit/extractors/language_coverage.rb +0 -37
- data/lib/fontisan/audit/extractors/licensing.rb +0 -79
- data/lib/fontisan/audit/extractors/metrics.rb +0 -103
- data/lib/fontisan/audit/extractors/opentype_layout.rb +0 -69
- data/lib/fontisan/audit/extractors/provenance.rb +0 -29
- data/lib/fontisan/audit/extractors/style.rb +0 -32
- data/lib/fontisan/audit/extractors/variation_detail.rb +0 -99
- data/lib/fontisan/audit/extractors.rb +0 -27
- data/lib/fontisan/audit/library_aggregator.rb +0 -83
- data/lib/fontisan/audit/library_auditor.rb +0 -90
- data/lib/fontisan/audit/registry.rb +0 -60
- data/lib/fontisan/audit/style_extractor.rb +0 -80
- data/lib/fontisan/audit.rb +0 -20
- data/lib/fontisan/cli/ucd_cli.rb +0 -97
- data/lib/fontisan/commands/audit_command.rb +0 -123
- data/lib/fontisan/commands/audit_compare_command.rb +0 -66
- data/lib/fontisan/commands/audit_library_command.rb +0 -46
- data/lib/fontisan/config/ucd.yml +0 -23
- data/lib/fontisan/formatters/audit_diff_text_renderer.rb +0 -122
- data/lib/fontisan/formatters/audit_text_renderer.rb +0 -324
- data/lib/fontisan/formatters/library_summary_text_renderer.rb +0 -99
- data/lib/fontisan/models/audit/audit_axis.rb +0 -30
- data/lib/fontisan/models/audit/audit_block.rb +0 -32
- data/lib/fontisan/models/audit/audit_diff.rb +0 -77
- data/lib/fontisan/models/audit/audit_report.rb +0 -153
- data/lib/fontisan/models/audit/codepoint_range.rb +0 -40
- data/lib/fontisan/models/audit/codepoint_set_diff.rb +0 -34
- data/lib/fontisan/models/audit/color_capabilities.rb +0 -93
- data/lib/fontisan/models/audit/duplicate_group.rb +0 -23
- data/lib/fontisan/models/audit/embedding_type.rb +0 -76
- data/lib/fontisan/models/audit/field_change.rb +0 -28
- data/lib/fontisan/models/audit/fs_selection_flags.rb +0 -61
- data/lib/fontisan/models/audit/gasp_range.rb +0 -63
- data/lib/fontisan/models/audit/hinting.rb +0 -93
- data/lib/fontisan/models/audit/library_summary.rb +0 -40
- data/lib/fontisan/models/audit/licensing.rb +0 -48
- data/lib/fontisan/models/audit/metrics.rb +0 -111
- data/lib/fontisan/models/audit/named_instance.rb +0 -41
- data/lib/fontisan/models/audit/opentype_layout.rb +0 -40
- data/lib/fontisan/models/audit/script_coverage_row.rb +0 -26
- data/lib/fontisan/models/audit/script_features.rb +0 -28
- data/lib/fontisan/models/audit/variation_detail.rb +0 -44
- data/lib/fontisan/models/audit.rb +0 -33
- data/lib/fontisan/models/ucd/ucd.rb +0 -38
- data/lib/fontisan/models/ucd/ucd_char.rb +0 -67
- data/lib/fontisan/models/ucd.rb +0 -19
- data/lib/fontisan/ucd/aggregator.rb +0 -73
- data/lib/fontisan/ucd/cache_manager.rb +0 -111
- data/lib/fontisan/ucd/config.rb +0 -59
- data/lib/fontisan/ucd/download_error.rb +0 -9
- data/lib/fontisan/ucd/downloader.rb +0 -88
- data/lib/fontisan/ucd/error.rb +0 -8
- data/lib/fontisan/ucd/index.rb +0 -103
- data/lib/fontisan/ucd/index_builder.rb +0 -107
- data/lib/fontisan/ucd/range_entry.rb +0 -56
- data/lib/fontisan/ucd/unknown_version_error.rb +0 -9
- data/lib/fontisan/ucd/version_resolver.rb +0 -79
- data/lib/fontisan/ucd.rb +0 -23
data/lib/fontisan/cli.rb
CHANGED
|
@@ -25,92 +25,14 @@ module Fontisan
|
|
|
25
25
|
desc: "Suppress non-error output",
|
|
26
26
|
aliases: "-q"
|
|
27
27
|
|
|
28
|
-
desc "ucd", "Manage local UCD cache (subcommands)", hide: true
|
|
29
|
-
subcommand "ucd", UcdCli
|
|
30
|
-
|
|
31
28
|
desc "cldr", "Manage local CLDR cache (subcommands)", hide: true
|
|
32
29
|
subcommand "cldr", CldrCli
|
|
33
30
|
|
|
34
|
-
desc "
|
|
35
|
-
|
|
36
|
-
Produce a complete per-face font audit report covering identity, style,
|
|
37
|
-
metrics, coverage (Unicode blocks/scripts), licensing, hinting, color
|
|
38
|
-
capabilities, variable font detail, and OpenType layout features.
|
|
39
|
-
|
|
40
|
-
For TTC/OTC/dfont collections, one report per face is produced. Use
|
|
41
|
-
--output to write reports to disk; --font-index to audit a single face.
|
|
42
|
-
|
|
43
|
-
Variants:
|
|
44
|
-
fontisan audit FONT.ttf
|
|
45
|
-
fontisan audit COLLECTION.ttc
|
|
46
|
-
fontisan audit DIR/ --recursive --summary
|
|
47
|
-
fontisan audit --compare A.ttf B.ttf
|
|
48
|
-
fontisan audit --compare A.yaml B.yaml
|
|
49
|
-
|
|
50
|
-
Output formats: text (default), yaml, json.
|
|
51
|
-
|
|
52
|
-
Use --brief for a fast inventory pass that skips metrics, hinting,
|
|
53
|
-
color, variable-font detail, OpenType layout, and UCD/CLDR
|
|
54
|
-
aggregation — only identity, style, licensing, and codepoint coverage.
|
|
55
|
-
DESC
|
|
56
|
-
option :font_index, type: :numeric,
|
|
57
|
-
desc: "Audit only this face in a collection (default: all)"
|
|
58
|
-
option :all_codepoints, type: :boolean, default: false,
|
|
59
|
-
desc: "Include the full per-codepoint list " \
|
|
60
|
-
"(defaults to compact range view)"
|
|
61
|
-
option :ucd_version, type: :string,
|
|
62
|
-
desc: "UCD version to aggregate against " \
|
|
63
|
-
"(default: configured default; 'latest' to probe)"
|
|
64
|
-
option :with_language_coverage, type: :boolean, default: false,
|
|
65
|
-
desc: "Compute coverage % per CLDR language " \
|
|
66
|
-
"(requires CLDR cache; auto-downloads)"
|
|
67
|
-
option :cldr_version, type: :string,
|
|
68
|
-
desc: "CLDR version (default: configured default; " \
|
|
69
|
-
"'latest' to probe)"
|
|
70
|
-
option :brief, type: :boolean, default: false,
|
|
71
|
-
desc: "Skip metrics/hinting/color/layout/UCD/CLDR for a " \
|
|
72
|
-
"fast inventory pass"
|
|
73
|
-
option :compare, type: :boolean, default: false,
|
|
74
|
-
desc: "Diff two fonts or two saved reports " \
|
|
75
|
-
"(requires exactly two PATHs)"
|
|
76
|
-
option :recursive, type: :boolean, default: false,
|
|
77
|
-
desc: "Audit every font under a directory tree " \
|
|
78
|
-
"(library mode)"
|
|
79
|
-
option :summary, type: :boolean, default: false,
|
|
80
|
-
desc: "Produce a LibrarySummary over a directory of fonts"
|
|
81
|
-
option :output, type: :string,
|
|
82
|
-
desc: "Output directory (collections/library) or file " \
|
|
83
|
-
"(single font / compare)",
|
|
84
|
-
aliases: "-o"
|
|
85
|
-
# Produce a complete font audit report, or diff two fonts/reports,
|
|
86
|
-
# or summarize a whole library.
|
|
87
|
-
#
|
|
88
|
-
# @param paths [Array<String>] one path (audit/library), or two paths (--compare)
|
|
89
|
-
def audit(*paths)
|
|
90
|
-
raise Thor::Error, "audit requires one PATH (or two with --compare)" if paths.empty?
|
|
91
|
-
|
|
92
|
-
if options[:compare]
|
|
93
|
-
unless paths.length == 2
|
|
94
|
-
raise Thor::Error,
|
|
95
|
-
"audit --compare requires exactly two paths"
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
return run_compare(paths[0], paths[1])
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
raise Thor::Error, "audit requires exactly one PATH" unless paths.length == 1
|
|
31
|
+
desc "ufo", "UFO source operations (build, convert, validate)"
|
|
32
|
+
subcommand "ufo", Fontisan::Ufo::Cli
|
|
102
33
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
raise Thor::Error,
|
|
106
|
-
"audit on a directory requires --recursive or --summary"
|
|
107
|
-
end
|
|
108
|
-
return run_library_audit(path) if library_mode?(path)
|
|
109
|
-
|
|
110
|
-
run_single_audit(path)
|
|
111
|
-
rescue Errno::ENOENT, Error, Thor::Error => e
|
|
112
|
-
handle_error(e)
|
|
113
|
-
end
|
|
34
|
+
desc "stitch", "Stitch glyphs from multiple source fonts into one output"
|
|
35
|
+
subcommand "stitch", StitcherCli
|
|
114
36
|
|
|
115
37
|
desc "info PATH", "Display font information"
|
|
116
38
|
option :brief, type: :boolean, default: false,
|
|
@@ -788,92 +710,6 @@ module Fontisan
|
|
|
788
710
|
puts output unless options[:quiet]
|
|
789
711
|
end
|
|
790
712
|
|
|
791
|
-
# Write audit reports to disk. If `target` is a directory (or there are
|
|
792
|
-
# multiple reports), one file per face is written under it. If `target`
|
|
793
|
-
# is a file path and there's exactly one report, that exact path is used.
|
|
794
|
-
#
|
|
795
|
-
# @param reports [Array<Models::Audit::AuditReport>]
|
|
796
|
-
# @param target [String] directory (collection) or file path (single)
|
|
797
|
-
# @param format [String] "yaml" or "json"
|
|
798
|
-
# @return [void]
|
|
799
|
-
def write_audit_outputs(reports, target, format)
|
|
800
|
-
sym_format = format.to_sym
|
|
801
|
-
|
|
802
|
-
if reports.one? && !Dir.exist?(target) && File.extname(target) != ""
|
|
803
|
-
File.write(target, serialize_report(reports.first, sym_format))
|
|
804
|
-
puts "Wrote #{target}" unless options[:quiet]
|
|
805
|
-
return
|
|
806
|
-
end
|
|
807
|
-
|
|
808
|
-
paths = Commands::AuditCommand.write_reports(reports, to: target,
|
|
809
|
-
format: sym_format)
|
|
810
|
-
paths.each { |p| puts "Wrote #{p}" unless options[:quiet] }
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
def run_single_audit(path)
|
|
814
|
-
cmd_options = options.dup
|
|
815
|
-
cmd_options.delete(:output)
|
|
816
|
-
# Audit's --brief selects a cheap extractor subset but still needs FULL
|
|
817
|
-
# font loading (Coverage reads cmap). Translate to :audit_brief so
|
|
818
|
-
# BaseCommand's :brief → METADATA shortcut does not fire.
|
|
819
|
-
cmd_options[:audit_brief] = cmd_options.delete(:brief) if cmd_options.key?(:brief)
|
|
820
|
-
command = Commands::AuditCommand.new(path, cmd_options)
|
|
821
|
-
reports = Array(command.run)
|
|
822
|
-
|
|
823
|
-
if options[:output]
|
|
824
|
-
write_audit_outputs(reports, options[:output], options[:format])
|
|
825
|
-
else
|
|
826
|
-
reports.each { |r| output_result(r) }
|
|
827
|
-
end
|
|
828
|
-
end
|
|
829
|
-
|
|
830
|
-
def run_compare(left_path, right_path)
|
|
831
|
-
cmd = Commands::AuditCompareCommand.new(left_path, right_path, options)
|
|
832
|
-
diff = cmd.run
|
|
833
|
-
return if options[:quiet]
|
|
834
|
-
|
|
835
|
-
if options[:output]
|
|
836
|
-
File.write(options[:output], serialize_report(diff, options[:format].to_sym))
|
|
837
|
-
puts "Wrote #{options[:output]}"
|
|
838
|
-
return
|
|
839
|
-
end
|
|
840
|
-
|
|
841
|
-
output_result(diff)
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
def run_library_audit(path)
|
|
845
|
-
cmd = Commands::AuditLibraryCommand.new(
|
|
846
|
-
path,
|
|
847
|
-
recursive: options[:recursive],
|
|
848
|
-
options: options.dup,
|
|
849
|
-
)
|
|
850
|
-
summary = cmd.run
|
|
851
|
-
announce_skipped(cmd.skipped)
|
|
852
|
-
return if options[:quiet]
|
|
853
|
-
|
|
854
|
-
if options[:output]
|
|
855
|
-
File.write(options[:output],
|
|
856
|
-
serialize_report(summary, options[:format].to_sym))
|
|
857
|
-
puts "Wrote #{options[:output]}"
|
|
858
|
-
return
|
|
859
|
-
end
|
|
860
|
-
|
|
861
|
-
output_result(summary)
|
|
862
|
-
end
|
|
863
|
-
|
|
864
|
-
# Library mode triggers when the path is a directory and either
|
|
865
|
-
# --recursive or --summary is requested. A single-file audit ignores
|
|
866
|
-
# both flags (a TTC is audited face-by-face via run_single_audit).
|
|
867
|
-
def library_mode?(path)
|
|
868
|
-
Dir.exist?(path) && (options[:recursive] || options[:summary])
|
|
869
|
-
end
|
|
870
|
-
|
|
871
|
-
def announce_skipped(skipped)
|
|
872
|
-
return if skipped.empty?
|
|
873
|
-
|
|
874
|
-
skipped.each { |p| warn "skipped #{p}" }
|
|
875
|
-
end
|
|
876
|
-
|
|
877
713
|
def serialize_report(report, format)
|
|
878
714
|
format == :json ? report.to_json : report.to_yaml
|
|
879
715
|
end
|
data/lib/fontisan/commands.rb
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
module Fontisan
|
|
6
6
|
module Commands
|
|
7
|
-
autoload :AuditCompareCommand, "fontisan/commands/audit_compare_command"
|
|
8
|
-
autoload :AuditCommand, "fontisan/commands/audit_command"
|
|
9
|
-
autoload :AuditLibraryCommand, "fontisan/commands/audit_library_command"
|
|
10
7
|
autoload :BaseCommand, "fontisan/commands/base_command"
|
|
11
8
|
autoload :ConvertCommand, "fontisan/commands/convert_command"
|
|
12
9
|
autoload :DumpTableCommand, "fontisan/commands/dump_table_command"
|
|
@@ -44,12 +44,6 @@ module Fontisan
|
|
|
44
44
|
format_collection_info(model)
|
|
45
45
|
when Models::CollectionBriefInfo
|
|
46
46
|
format_collection_brief_info(model)
|
|
47
|
-
when Models::Audit::AuditReport
|
|
48
|
-
Formatters::AuditTextRenderer.new(model).render
|
|
49
|
-
when Models::Audit::AuditDiff
|
|
50
|
-
Formatters::AuditDiffTextRenderer.new(model).render
|
|
51
|
-
when Models::Audit::LibrarySummary
|
|
52
|
-
Formatters::LibrarySummaryTextRenderer.new(model).render
|
|
53
47
|
else
|
|
54
48
|
model.to_s
|
|
55
49
|
end
|
data/lib/fontisan/formatters.rb
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
module Fontisan
|
|
6
6
|
module Formatters
|
|
7
|
-
autoload :AuditDiffTextRenderer, "fontisan/formatters/audit_diff_text_renderer"
|
|
8
|
-
autoload :AuditTextRenderer, "fontisan/formatters/audit_text_renderer"
|
|
9
|
-
autoload :LibrarySummaryTextRenderer, "fontisan/formatters/library_summary_text_renderer"
|
|
10
7
|
autoload :TextFormatter, "fontisan/formatters/text_formatter"
|
|
11
8
|
end
|
|
12
9
|
end
|
data/lib/fontisan/hints.rb
CHANGED
|
@@ -7,10 +7,13 @@ module Fontisan
|
|
|
7
7
|
autoload :HintConverter, "fontisan/hints/hint_converter"
|
|
8
8
|
autoload :HintValidator, "fontisan/hints/hint_validator"
|
|
9
9
|
autoload :PostScriptHintApplier, "fontisan/hints/postscript_hint_applier"
|
|
10
|
-
autoload :PostScriptHintExtractor,
|
|
10
|
+
autoload :PostScriptHintExtractor,
|
|
11
|
+
"fontisan/hints/postscript_hint_extractor"
|
|
11
12
|
autoload :TrueTypeHintApplier, "fontisan/hints/truetype_hint_applier"
|
|
12
13
|
autoload :TrueTypeHintExtractor, "fontisan/hints/truetype_hint_extractor"
|
|
13
|
-
autoload :TrueTypeInstructionAnalyzer,
|
|
14
|
-
|
|
14
|
+
autoload :TrueTypeInstructionAnalyzer,
|
|
15
|
+
"fontisan/hints/truetype_instruction_analyzer"
|
|
16
|
+
autoload :TrueTypeInstructionGenerator,
|
|
17
|
+
"fontisan/hints/truetype_instruction_generator"
|
|
15
18
|
end
|
|
16
19
|
end
|
data/lib/fontisan/models.rb
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
module Fontisan
|
|
6
6
|
module Models
|
|
7
|
-
autoload :AllScriptsFeaturesInfo,
|
|
8
|
-
|
|
7
|
+
autoload :AllScriptsFeaturesInfo,
|
|
8
|
+
"fontisan/models/all_scripts_features_info"
|
|
9
9
|
autoload :AxisInfo, "fontisan/models/variable_font_info"
|
|
10
10
|
autoload :BitmapGlyph, "fontisan/models/bitmap_glyph"
|
|
11
11
|
autoload :BitmapStrike, "fontisan/models/bitmap_strike"
|
|
@@ -13,7 +13,8 @@ module Fontisan
|
|
|
13
13
|
autoload :CollectionFontSummary, "fontisan/models/collection_font_summary"
|
|
14
14
|
autoload :CollectionInfo, "fontisan/models/collection_info"
|
|
15
15
|
autoload :CollectionListInfo, "fontisan/models/collection_list_info"
|
|
16
|
-
autoload :CollectionValidationReport,
|
|
16
|
+
autoload :CollectionValidationReport,
|
|
17
|
+
"fontisan/models/collection_validation_report"
|
|
17
18
|
autoload :Cldr, "fontisan/models/cldr"
|
|
18
19
|
autoload :ColorGlyph, "fontisan/models/color_glyph"
|
|
19
20
|
autoload :ColorLayer, "fontisan/models/color_layer"
|
|
@@ -38,7 +39,6 @@ module Fontisan
|
|
|
38
39
|
autoload :TableInfo, "fontisan/models/table_info"
|
|
39
40
|
autoload :TableSharingInfo, "fontisan/models/table_sharing_info"
|
|
40
41
|
autoload :Ttx, "fontisan/models/ttx/ttfont"
|
|
41
|
-
autoload :Ucd, "fontisan/models/ucd"
|
|
42
42
|
autoload :UnicodeMapping, "fontisan/models/unicode_mappings"
|
|
43
43
|
autoload :UnicodeMappings, "fontisan/models/unicode_mappings"
|
|
44
44
|
autoload :ValidationReport, "fontisan/models/validation_report"
|
|
@@ -6,9 +6,11 @@ module Fontisan
|
|
|
6
6
|
module Pipeline
|
|
7
7
|
module Strategies
|
|
8
8
|
autoload :BaseStrategy, "fontisan/pipeline/strategies/base_strategy"
|
|
9
|
-
autoload :InstanceStrategy,
|
|
9
|
+
autoload :InstanceStrategy,
|
|
10
|
+
"fontisan/pipeline/strategies/instance_strategy"
|
|
10
11
|
autoload :NamedStrategy, "fontisan/pipeline/strategies/named_strategy"
|
|
11
|
-
autoload :PreserveStrategy,
|
|
12
|
+
autoload :PreserveStrategy,
|
|
13
|
+
"fontisan/pipeline/strategies/preserve_strategy"
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
end
|
data/lib/fontisan/pipeline.rb
CHANGED
|
@@ -7,7 +7,8 @@ module Fontisan
|
|
|
7
7
|
autoload :FormatDetector, "fontisan/pipeline/format_detector"
|
|
8
8
|
autoload :OutputWriter, "fontisan/pipeline/output_writer"
|
|
9
9
|
autoload :Strategies, "fontisan/pipeline/strategies/base_strategy"
|
|
10
|
-
autoload :TransformationPipeline,
|
|
10
|
+
autoload :TransformationPipeline,
|
|
11
|
+
"fontisan/pipeline/transformation_pipeline"
|
|
11
12
|
autoload :VariationResolver, "fontisan/pipeline/variation_resolver"
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fontisan
|
|
4
|
+
class Stitcher
|
|
5
|
+
module Selector
|
|
6
|
+
# Include an explicit list of codepoints.
|
|
7
|
+
class Codepoints
|
|
8
|
+
attr_reader :codepoints
|
|
9
|
+
|
|
10
|
+
def initialize(codepoints)
|
|
11
|
+
@codepoints = codepoints
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(source, bindings)
|
|
15
|
+
@codepoints.each do |cp|
|
|
16
|
+
gid = source.gid_for_codepoint(cp)
|
|
17
|
+
next unless gid
|
|
18
|
+
|
|
19
|
+
bindings << {
|
|
20
|
+
codepoint: cp,
|
|
21
|
+
source: source,
|
|
22
|
+
donor_gid: gid,
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fontisan
|
|
4
|
+
class Stitcher
|
|
5
|
+
module Selector
|
|
6
|
+
# Include a single glyph by its donor gid. Used for unencoded
|
|
7
|
+
# glyphs (.notdef, spaces, format-specific specials).
|
|
8
|
+
class Gid
|
|
9
|
+
attr_reader :gid
|
|
10
|
+
|
|
11
|
+
def initialize(gid)
|
|
12
|
+
@gid = gid
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply(source, bindings)
|
|
16
|
+
bindings << {
|
|
17
|
+
codepoint: nil,
|
|
18
|
+
source: source,
|
|
19
|
+
donor_gid: @gid,
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fontisan
|
|
4
|
+
class Stitcher
|
|
5
|
+
module Selector
|
|
6
|
+
# Include every codepoint in a Range (e.g. 0x41..0x5A = A-Z).
|
|
7
|
+
# Glyphs missing from the source are silently skipped.
|
|
8
|
+
class Range
|
|
9
|
+
attr_reader :range
|
|
10
|
+
|
|
11
|
+
def initialize(range)
|
|
12
|
+
@range = range
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply(source, bindings)
|
|
16
|
+
@range.each do |cp|
|
|
17
|
+
gid = source.gid_for_codepoint(cp)
|
|
18
|
+
next unless gid
|
|
19
|
+
|
|
20
|
+
bindings << {
|
|
21
|
+
codepoint: cp,
|
|
22
|
+
source: source,
|
|
23
|
+
donor_gid: gid,
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fontisan
|
|
4
|
+
class Stitcher
|
|
5
|
+
# Selectors decide which glyphs from a source to include in the
|
|
6
|
+
# stitched font. Each selector appends to the Stitcher's bindings
|
|
7
|
+
# list. OCP: adding a new way to select = adding a new Selector
|
|
8
|
+
# class + a registry entry.
|
|
9
|
+
module Selector
|
|
10
|
+
autoload :Range, "fontisan/stitcher/selector/range"
|
|
11
|
+
autoload :Codepoints, "fontisan/stitcher/selector/codepoints"
|
|
12
|
+
autoload :Gid, "fontisan/stitcher/selector/gid"
|
|
13
|
+
|
|
14
|
+
REGISTRY = {
|
|
15
|
+
range: Range,
|
|
16
|
+
codepoints: Codepoints,
|
|
17
|
+
gid: Gid,
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def self.resolve(name)
|
|
21
|
+
REGISTRY[name.to_sym] or
|
|
22
|
+
raise ArgumentError, "unknown selector: #{name.inspect}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fontisan
|
|
4
|
+
class Stitcher
|
|
5
|
+
# Wraps a source font (UFO or loaded TTF/OTF) behind a single
|
|
6
|
+
# extraction API used by the selectors.
|
|
7
|
+
#
|
|
8
|
+
# For UFO sources, glyphs are accessed by name directly. For TTF
|
|
9
|
+
# or OTF sources, the source is lazily converted to a UFO::Font
|
|
10
|
+
# via Ufo::Convert::FromBinData on first glyph access, then cached.
|
|
11
|
+
# This is O(n) in donor glyph count but amortized across all
|
|
12
|
+
# codepoint extractions from that donor.
|
|
13
|
+
class Source
|
|
14
|
+
attr_reader :font
|
|
15
|
+
|
|
16
|
+
def initialize(font)
|
|
17
|
+
@font = font
|
|
18
|
+
@ufo_cache = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Symbol] :ufo, :ttf, :otf
|
|
22
|
+
def format
|
|
23
|
+
case @font
|
|
24
|
+
when Fontisan::Ufo::Font then :ufo
|
|
25
|
+
when Fontisan::TrueTypeFont then :ttf
|
|
26
|
+
when Fontisan::OpenTypeFont then :otf
|
|
27
|
+
else :unknown
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Find the gid for a Unicode codepoint in this source.
|
|
32
|
+
# @param codepoint [Integer]
|
|
33
|
+
# @return [Integer, nil]
|
|
34
|
+
def gid_for_codepoint(codepoint)
|
|
35
|
+
case @font
|
|
36
|
+
when Fontisan::Ufo::Font then ufo_gid_for(codepoint)
|
|
37
|
+
else bin_data_gid_for(codepoint)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Extract a glyph by gid.
|
|
42
|
+
# @param gid [Integer]
|
|
43
|
+
# @return [Fontisan::Ufo::Glyph, nil]
|
|
44
|
+
def glyph_for_gid(gid)
|
|
45
|
+
case @font
|
|
46
|
+
when Fontisan::Ufo::Font then ufo_glyph_at(gid)
|
|
47
|
+
else converted_ufo_glyph_at(gid)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# ---------- UFO source ----------
|
|
54
|
+
|
|
55
|
+
def ufo_gid_for(codepoint)
|
|
56
|
+
@font.glyphs.each_with_index do |(_name, glyph), index|
|
|
57
|
+
return index if glyph.unicodes.include?(codepoint)
|
|
58
|
+
end
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ufo_glyph_at(gid)
|
|
63
|
+
names = @font.glyphs.keys
|
|
64
|
+
name = names[gid]
|
|
65
|
+
return nil unless name
|
|
66
|
+
|
|
67
|
+
@font.glyph(name)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# ---------- TTF/OTF source ----------
|
|
71
|
+
|
|
72
|
+
def bin_data_gid_for(codepoint)
|
|
73
|
+
cmap = @font.table("cmap")
|
|
74
|
+
return nil unless cmap
|
|
75
|
+
|
|
76
|
+
cmap.unicode_mappings[codepoint]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Lazily convert the loaded TTF/OTF to a UFO::Font, then
|
|
80
|
+
# extract glyphs from the cached UFO model.
|
|
81
|
+
def converted_ufo
|
|
82
|
+
return @ufo_cache if @ufo_cache
|
|
83
|
+
|
|
84
|
+
@ufo_cache = Fontisan::Ufo::Convert::FromBinData.convert(@font)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def converted_ufo_glyph_at(gid)
|
|
88
|
+
ufo = converted_ufo
|
|
89
|
+
names = ufo.glyphs.keys
|
|
90
|
+
name = names[gid]
|
|
91
|
+
return nil unless name
|
|
92
|
+
|
|
93
|
+
ufo.glyph(name)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|