fontisan 0.2.17 → 0.2.22
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_todo.yml +14 -90
- data/README.adoc +257 -1
- data/docs/.vitepress/config.ts +68 -8
- data/docs/.vitepress/theme/style.css +570 -272
- data/docs/CONVERSION_GUIDE.adoc +31 -8
- data/docs/EXTRACT_TTC_MIGRATION.md +1 -1
- data/docs/WOFF_WOFF2_FORMATS.adoc +53 -0
- data/docs/api/conversion-options.md +37 -14
- data/docs/cli/audit.md +337 -0
- data/docs/cli/convert.md +20 -1
- data/docs/cli/index.md +31 -0
- data/docs/guide/color.md +1 -1
- data/docs/guide/conversion/options.md +32 -3
- data/docs/guide/conversion/ttf-otf.md +1 -1
- data/docs/guide/conversion/type1.md +1 -1
- data/docs/guide/conversion/web.md +91 -32
- data/docs/guide/conversion.md +6 -5
- data/docs/guide/formats/woff.md +35 -11
- data/docs/guide/index.md +2 -2
- data/docs/guide/migrations/extract-ttc.md +1 -1
- data/docs/guide/quick-start.md +4 -4
- data/docs/guide/type1.md +4 -4
- data/docs/guide/woff.md +19 -17
- data/docs/index.md +2 -0
- data/docs/lychee.toml +5 -1
- data/docs/package.json +1 -1
- data/docs/public/robots.txt +4 -0
- data/docs/scripts/post-build.mjs +81 -0
- data/lib/fontisan/audit/codepoint_range_coalescer.rb +41 -0
- data/lib/fontisan/audit/context.rb +122 -0
- data/lib/fontisan/audit/differ.rb +124 -0
- data/lib/fontisan/audit/extractors/aggregations.rb +54 -0
- data/lib/fontisan/audit/extractors/base.rb +26 -0
- data/lib/fontisan/audit/extractors/color_capabilities.rb +141 -0
- data/lib/fontisan/audit/extractors/coverage.rb +48 -0
- data/lib/fontisan/audit/extractors/hinting.rb +197 -0
- data/lib/fontisan/audit/extractors/identity.rb +52 -0
- data/lib/fontisan/audit/extractors/language_coverage.rb +37 -0
- data/lib/fontisan/audit/extractors/licensing.rb +79 -0
- data/lib/fontisan/audit/extractors/metrics.rb +103 -0
- data/lib/fontisan/audit/extractors/opentype_layout.rb +69 -0
- data/lib/fontisan/audit/extractors/provenance.rb +29 -0
- data/lib/fontisan/audit/extractors/style.rb +32 -0
- data/lib/fontisan/audit/extractors/variation_detail.rb +99 -0
- data/lib/fontisan/audit/extractors.rb +27 -0
- data/lib/fontisan/audit/library_aggregator.rb +83 -0
- data/lib/fontisan/audit/library_auditor.rb +90 -0
- data/lib/fontisan/audit/registry.rb +60 -0
- data/lib/fontisan/audit/style_extractor.rb +80 -0
- data/lib/fontisan/audit.rb +20 -0
- data/lib/fontisan/base_collection.rb +23 -9
- data/lib/fontisan/binary/structures.rb +0 -2
- data/lib/fontisan/binary.rb +11 -0
- data/lib/fontisan/cldr/aggregator.rb +33 -0
- data/lib/fontisan/cldr/cache_manager.rb +110 -0
- data/lib/fontisan/cldr/config.rb +59 -0
- data/lib/fontisan/cldr/download_error.rb +9 -0
- data/lib/fontisan/cldr/downloader.rb +79 -0
- data/lib/fontisan/cldr/error.rb +8 -0
- data/lib/fontisan/cldr/index.rb +64 -0
- data/lib/fontisan/cldr/index_builder.rb +72 -0
- data/lib/fontisan/cldr/unicode_set_parser.rb +172 -0
- data/lib/fontisan/cldr/unknown_version_error.rb +9 -0
- data/lib/fontisan/cldr/version_resolver.rb +91 -0
- data/lib/fontisan/cldr.rb +23 -0
- data/lib/fontisan/cli/cldr_cli.rb +85 -0
- data/lib/fontisan/cli/ucd_cli.rb +97 -0
- data/lib/fontisan/cli.rb +201 -2
- data/lib/fontisan/collection/builder.rb +0 -4
- data/lib/fontisan/collection/dfont_builder.rb +0 -4
- data/lib/fontisan/collection/shared_logic.rb +0 -2
- data/lib/fontisan/collection/writer.rb +0 -3
- data/lib/fontisan/collection.rb +15 -0
- data/lib/fontisan/commands/audit_command.rb +123 -0
- data/lib/fontisan/commands/audit_compare_command.rb +66 -0
- data/lib/fontisan/commands/audit_library_command.rb +46 -0
- data/lib/fontisan/commands/base_command.rb +0 -3
- data/lib/fontisan/commands/convert_command.rb +25 -20
- data/lib/fontisan/commands/dump_table_command.rb +0 -3
- data/lib/fontisan/commands/export_command.rb +0 -4
- data/lib/fontisan/commands/features_command.rb +0 -3
- data/lib/fontisan/commands/instance_command.rb +0 -5
- data/lib/fontisan/commands/ls_command.rb +0 -6
- data/lib/fontisan/commands/optical_size_command.rb +0 -3
- data/lib/fontisan/commands/pack_command.rb +0 -5
- data/lib/fontisan/commands/scripts_command.rb +0 -2
- data/lib/fontisan/commands/subset_command.rb +0 -3
- data/lib/fontisan/commands/unicode_command.rb +0 -3
- data/lib/fontisan/commands/unpack_command.rb +0 -7
- data/lib/fontisan/commands/validate_command.rb +0 -8
- data/lib/fontisan/commands/variable_command.rb +0 -3
- data/lib/fontisan/commands.rb +29 -0
- data/lib/fontisan/config/cldr.yml +22 -0
- data/lib/fontisan/config/conversion_matrix.yml +38 -0
- data/lib/fontisan/config/ucd.yml +23 -0
- data/lib/fontisan/constants.rb +19 -0
- data/lib/fontisan/conversion_options.rb +30 -19
- data/lib/fontisan/converters/cff_table_builder.rb +0 -3
- data/lib/fontisan/converters/collection_converter.rb +0 -8
- data/lib/fontisan/converters/conversion_strategy.rb +161 -46
- data/lib/fontisan/converters/format_converter.rb +143 -32
- data/lib/fontisan/converters/glyf_table_builder.rb +0 -2
- data/lib/fontisan/converters/outline_converter.rb +0 -19
- data/lib/fontisan/converters/outline_extraction.rb +0 -5
- data/lib/fontisan/converters/outline_optimizer.rb +0 -5
- data/lib/fontisan/converters/svg_generator.rb +0 -4
- data/lib/fontisan/converters/table_copier.rb +0 -2
- data/lib/fontisan/converters/type1_converter.rb +0 -11
- data/lib/fontisan/converters/woff2_encoder.rb +49 -20
- data/lib/fontisan/converters/woff_writer.rb +211 -282
- data/lib/fontisan/converters.rb +21 -0
- data/lib/fontisan/dfont_collection.rb +29 -10
- data/lib/fontisan/export/exporter.rb +0 -6
- data/lib/fontisan/export/transformers/font_to_ttx.rb +0 -9
- data/lib/fontisan/export/transformers/head_transformer.rb +0 -2
- data/lib/fontisan/export/transformers/hhea_transformer.rb +0 -2
- data/lib/fontisan/export/transformers/maxp_transformer.rb +0 -2
- data/lib/fontisan/export/transformers/name_transformer.rb +0 -2
- data/lib/fontisan/export/transformers/os2_transformer.rb +0 -2
- data/lib/fontisan/export/transformers/post_transformer.rb +0 -2
- data/lib/fontisan/export/transformers.rb +17 -0
- data/lib/fontisan/export.rb +13 -0
- data/lib/fontisan/font_loader.rb +14 -19
- data/lib/fontisan/font_writer.rb +0 -1
- data/lib/fontisan/formatters/audit_diff_text_renderer.rb +122 -0
- data/lib/fontisan/formatters/audit_text_renderer.rb +324 -0
- data/lib/fontisan/formatters/library_summary_text_renderer.rb +99 -0
- data/lib/fontisan/formatters/text_formatter.rb +6 -0
- data/lib/fontisan/formatters.rb +12 -0
- data/lib/fontisan/hints/hint_converter.rb +0 -1
- data/lib/fontisan/hints/postscript_hint_applier.rb +0 -9
- data/lib/fontisan/hints/postscript_hint_extractor.rb +0 -2
- data/lib/fontisan/hints/truetype_hint_extractor.rb +0 -2
- data/lib/fontisan/hints.rb +16 -0
- data/lib/fontisan/metrics_calculator.rb +0 -2
- data/lib/fontisan/models/all_scripts_features_info.rb +0 -1
- data/lib/fontisan/models/audit/audit_axis.rb +30 -0
- data/lib/fontisan/models/audit/audit_block.rb +32 -0
- data/lib/fontisan/models/audit/audit_diff.rb +77 -0
- data/lib/fontisan/models/audit/audit_report.rb +153 -0
- data/lib/fontisan/models/audit/codepoint_range.rb +40 -0
- data/lib/fontisan/models/audit/codepoint_set_diff.rb +34 -0
- data/lib/fontisan/models/audit/color_capabilities.rb +93 -0
- data/lib/fontisan/models/audit/duplicate_group.rb +23 -0
- data/lib/fontisan/models/audit/embedding_type.rb +76 -0
- data/lib/fontisan/models/audit/field_change.rb +28 -0
- data/lib/fontisan/models/audit/fs_selection_flags.rb +61 -0
- data/lib/fontisan/models/audit/gasp_range.rb +63 -0
- data/lib/fontisan/models/audit/hinting.rb +93 -0
- data/lib/fontisan/models/audit/library_summary.rb +40 -0
- data/lib/fontisan/models/audit/licensing.rb +48 -0
- data/lib/fontisan/models/audit/metrics.rb +111 -0
- data/lib/fontisan/models/audit/named_instance.rb +41 -0
- data/lib/fontisan/models/audit/opentype_layout.rb +40 -0
- data/lib/fontisan/models/audit/script_coverage_row.rb +26 -0
- data/lib/fontisan/models/audit/script_features.rb +28 -0
- data/lib/fontisan/models/audit/variation_detail.rb +44 -0
- data/lib/fontisan/models/audit.rb +33 -0
- data/lib/fontisan/models/cldr/language_coverage.rb +31 -0
- data/lib/fontisan/models/cldr.rb +12 -0
- data/lib/fontisan/models/collection_brief_info.rb +0 -1
- data/lib/fontisan/models/collection_info.rb +0 -2
- data/lib/fontisan/models/collection_list_info.rb +0 -1
- data/lib/fontisan/models/collection_validation_report.rb +0 -2
- data/lib/fontisan/models/color_glyph.rb +0 -1
- data/lib/fontisan/models/font_report.rb +0 -1
- data/lib/fontisan/models/ttx/tables.rb +21 -0
- data/lib/fontisan/models/ttx/ttfont.rb +0 -8
- data/lib/fontisan/models/ttx.rb +14 -0
- data/lib/fontisan/models/ucd/ucd.rb +38 -0
- data/lib/fontisan/models/ucd/ucd_char.rb +67 -0
- data/lib/fontisan/models/ucd.rb +19 -0
- data/lib/fontisan/models.rb +47 -0
- data/lib/fontisan/open_type_collection.rb +6 -5
- data/lib/fontisan/open_type_font.rb +8 -2
- data/lib/fontisan/open_type_font_extensions.rb +9 -9
- data/lib/fontisan/optimizers/pattern_analyzer.rb +0 -1
- data/lib/fontisan/optimizers.rb +14 -0
- data/lib/fontisan/outline_extractor.rb +0 -2
- data/lib/fontisan/parsers/dfont_parser.rb +0 -1
- data/lib/fontisan/parsers.rb +10 -0
- data/lib/fontisan/pipeline/format_detector.rb +29 -102
- data/lib/fontisan/pipeline/output_writer.rb +11 -9
- data/lib/fontisan/pipeline/strategies/instance_strategy.rb +0 -4
- data/lib/fontisan/pipeline/strategies/named_strategy.rb +0 -4
- data/lib/fontisan/pipeline/strategies/preserve_strategy.rb +0 -2
- data/lib/fontisan/pipeline/strategies.rb +14 -0
- data/lib/fontisan/pipeline/transformation_pipeline.rb +0 -7
- data/lib/fontisan/pipeline/variation_resolver.rb +0 -7
- data/lib/fontisan/pipeline.rb +13 -0
- data/lib/fontisan/sfnt_font.rb +29 -14
- data/lib/fontisan/sfnt_table.rb +0 -4
- data/lib/fontisan/subset/builder.rb +0 -6
- data/lib/fontisan/subset.rb +13 -0
- data/lib/fontisan/svg/font_generator.rb +0 -4
- data/lib/fontisan/svg/glyph_generator.rb +0 -2
- data/lib/fontisan/svg.rb +12 -0
- data/lib/fontisan/tables/cbdt.rb +0 -1
- data/lib/fontisan/tables/cblc.rb +0 -1
- data/lib/fontisan/tables/cff/charset.rb +0 -1
- data/lib/fontisan/tables/cff/charstring.rb +0 -1
- data/lib/fontisan/tables/cff/charstring_rebuilder.rb +0 -4
- data/lib/fontisan/tables/cff/charstrings_index.rb +0 -3
- data/lib/fontisan/tables/cff/dict.rb +0 -1
- data/lib/fontisan/tables/cff/encoding.rb +0 -1
- data/lib/fontisan/tables/cff/header.rb +0 -2
- data/lib/fontisan/tables/cff/hint_operation_injector.rb +0 -2
- data/lib/fontisan/tables/cff/index.rb +0 -1
- data/lib/fontisan/tables/cff/private_dict.rb +0 -2
- data/lib/fontisan/tables/cff/private_dict_writer.rb +0 -2
- data/lib/fontisan/tables/cff/table_builder.rb +0 -6
- data/lib/fontisan/tables/cff/top_dict.rb +0 -2
- data/lib/fontisan/tables/cff.rb +22 -15
- data/lib/fontisan/tables/cff2/charstring_parser.rb +0 -2
- data/lib/fontisan/tables/cff2/table_builder.rb +0 -11
- data/lib/fontisan/tables/cff2/table_reader.rb +0 -2
- data/lib/fontisan/tables/cff2.rb +13 -14
- data/lib/fontisan/tables/cmap.rb +24 -2
- data/lib/fontisan/tables/cmap_table.rb +0 -3
- data/lib/fontisan/tables/colr.rb +0 -1
- data/lib/fontisan/tables/cpal.rb +0 -1
- data/lib/fontisan/tables/cvar.rb +0 -2
- data/lib/fontisan/tables/fvar.rb +0 -1
- data/lib/fontisan/tables/glyf/compound_glyph_resolver.rb +0 -2
- data/lib/fontisan/tables/glyf/glyph_builder.rb +0 -3
- data/lib/fontisan/tables/glyf.rb +0 -6
- data/lib/fontisan/tables/glyf_table.rb +0 -3
- data/lib/fontisan/tables/gpos.rb +0 -2
- data/lib/fontisan/tables/gsub.rb +0 -2
- data/lib/fontisan/tables/gvar.rb +0 -2
- data/lib/fontisan/tables/head.rb +0 -2
- data/lib/fontisan/tables/head_table.rb +0 -3
- data/lib/fontisan/tables/hhea.rb +0 -2
- data/lib/fontisan/tables/hhea_table.rb +0 -3
- data/lib/fontisan/tables/hmtx.rb +0 -2
- data/lib/fontisan/tables/hmtx_table.rb +0 -3
- data/lib/fontisan/tables/hvar.rb +0 -3
- data/lib/fontisan/tables/loca.rb +0 -2
- data/lib/fontisan/tables/loca_table.rb +0 -3
- data/lib/fontisan/tables/maxp.rb +0 -2
- data/lib/fontisan/tables/maxp_table.rb +0 -3
- data/lib/fontisan/tables/mvar.rb +0 -3
- data/lib/fontisan/tables/name.rb +0 -2
- data/lib/fontisan/tables/name_table.rb +0 -3
- data/lib/fontisan/tables/os2_table.rb +0 -3
- data/lib/fontisan/tables/post_table.rb +0 -3
- data/lib/fontisan/tables/sbix.rb +0 -1
- data/lib/fontisan/tables/svg.rb +0 -1
- data/lib/fontisan/tables/variation_common.rb +0 -1
- data/lib/fontisan/tables/vvar.rb +0 -3
- data/lib/fontisan/tables.rb +54 -0
- data/lib/fontisan/true_type_collection.rb +6 -14
- data/lib/fontisan/true_type_font.rb +8 -2
- data/lib/fontisan/true_type_font_extensions.rb +9 -9
- data/lib/fontisan/type1/afm_generator.rb +0 -4
- data/lib/fontisan/type1/conversion_options.rb +0 -2
- data/lib/fontisan/type1/encodings.rb +0 -2
- data/lib/fontisan/type1/generator.rb +0 -8
- data/lib/fontisan/type1/pfa_generator.rb +0 -3
- data/lib/fontisan/type1/pfb_generator.rb +0 -5
- data/lib/fontisan/type1/pfm_generator.rb +0 -4
- data/lib/fontisan/type1.rb +42 -69
- data/lib/fontisan/type1_font.rb +40 -11
- data/lib/fontisan/ucd/aggregator.rb +73 -0
- data/lib/fontisan/ucd/cache_manager.rb +111 -0
- data/lib/fontisan/ucd/config.rb +59 -0
- data/lib/fontisan/ucd/download_error.rb +9 -0
- data/lib/fontisan/ucd/downloader.rb +88 -0
- data/lib/fontisan/ucd/error.rb +8 -0
- data/lib/fontisan/ucd/index.rb +103 -0
- data/lib/fontisan/ucd/index_builder.rb +107 -0
- data/lib/fontisan/ucd/range_entry.rb +56 -0
- data/lib/fontisan/ucd/unknown_version_error.rb +9 -0
- data/lib/fontisan/ucd/version_resolver.rb +79 -0
- data/lib/fontisan/ucd.rb +23 -0
- data/lib/fontisan/utilities/checksum_calculator.rb +0 -1
- data/lib/fontisan/utilities.rb +10 -0
- data/lib/fontisan/utils.rb +10 -0
- data/lib/fontisan/validation/collection_validator.rb +0 -2
- data/lib/fontisan/validation.rb +9 -0
- data/lib/fontisan/validators/basic_validator.rb +0 -2
- data/lib/fontisan/validators/font_book_validator.rb +0 -2
- data/lib/fontisan/validators/opentype_validator.rb +0 -2
- data/lib/fontisan/validators/profile_loader.rb +0 -5
- data/lib/fontisan/validators/validator.rb +0 -2
- data/lib/fontisan/validators/web_font_validator.rb +0 -2
- data/lib/fontisan/validators.rb +14 -0
- data/lib/fontisan/variable/delta_applicator.rb +0 -4
- data/lib/fontisan/variable/instancer.rb +0 -3
- data/lib/fontisan/variable/static_font_builder.rb +0 -3
- data/lib/fontisan/variable.rb +16 -0
- data/lib/fontisan/variation/blend_applier.rb +0 -2
- data/lib/fontisan/variation/cache.rb +0 -2
- data/lib/fontisan/variation/converter.rb +0 -3
- data/lib/fontisan/variation/data_extractor.rb +0 -2
- data/lib/fontisan/variation/delta_applier.rb +0 -5
- data/lib/fontisan/variation/inspector.rb +0 -1
- data/lib/fontisan/variation/instance_generator.rb +0 -6
- data/lib/fontisan/variation/instance_writer.rb +0 -5
- data/lib/fontisan/variation/metrics_adjuster.rb +0 -4
- data/lib/fontisan/variation/optimizer.rb +0 -3
- data/lib/fontisan/variation/parallel_generator.rb +0 -3
- data/lib/fontisan/variation/subsetter.rb +0 -4
- data/lib/fontisan/variation/tuple_variation_header.rb +0 -2
- data/lib/fontisan/variation/variable_svg_generator.rb +0 -3
- data/lib/fontisan/variation/variation_context.rb +0 -3
- data/lib/fontisan/variation/variation_preserver.rb +0 -3
- data/lib/fontisan/variation.rb +31 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff2.rb +13 -0
- data/lib/fontisan/woff2_font.rb +31 -9
- data/lib/fontisan/woff_font.rb +31 -2
- data/lib/fontisan.rb +124 -196
- metadata +114 -7
- data/fontisan.gemspec +0 -48
|
@@ -2,45 +2,171 @@
|
|
|
2
2
|
|
|
3
3
|
module Fontisan
|
|
4
4
|
module Converters
|
|
5
|
-
# Interface module
|
|
5
|
+
# Interface module and declarative options DSL for conversion strategies
|
|
6
6
|
#
|
|
7
7
|
# [`ConversionStrategy`](lib/fontisan/converters/conversion_strategy.rb)
|
|
8
|
-
# defines the contract that all conversion strategy classes must implement
|
|
9
|
-
#
|
|
10
|
-
# different conversion types (TTF→OTF, OTF→TTF, same-format copying).
|
|
8
|
+
# defines the contract that all conversion strategy classes must implement,
|
|
9
|
+
# plus a declarative DSL for declaring the options each strategy accepts.
|
|
11
10
|
#
|
|
12
|
-
#
|
|
13
|
-
# - convert(font, options) - Perform the actual conversion
|
|
14
|
-
# - supported_conversions - Return array of [source, target] format pairs
|
|
15
|
-
# - validate(font, target_format) - Validate conversion is possible
|
|
11
|
+
# ## Why a declarative options DSL
|
|
16
12
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
13
|
+
# Each format has its own spec-mandated knobs (WOFF: zlib level,
|
|
14
|
+
# WOFF2: Brotli quality, etc.). Letting each strategy declare its own
|
|
15
|
+
# options keeps the schema with the code that consumes it (encapsulation),
|
|
16
|
+
# and makes adding a new format a pure additive change (OCP): write a new
|
|
17
|
+
# strategy class, declare its options, done — no edits to central option
|
|
18
|
+
# lists, the CLI option parser, or ConversionOptions.
|
|
19
19
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
20
|
+
# The strategy is also the sole validator of its own options. The
|
|
21
|
+
# runtime check at `FormatConverter#convert` calls
|
|
22
|
+
# `strategy.class.validate_options!` to enforce the format ↔ option
|
|
23
|
+
# mapping (e.g., rejecting `--zlib-level` on a WOFF2 conversion). This
|
|
24
|
+
# is the MECE guarantee: every option belongs to exactly one strategy,
|
|
25
|
+
# and a strategy rejects anything it did not declare.
|
|
23
26
|
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# tables
|
|
28
|
-
# end
|
|
27
|
+
# @example Declaring options
|
|
28
|
+
# class WoffWriter
|
|
29
|
+
# include ConversionStrategy
|
|
29
30
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
31
|
+
# option :zlib_level, type: :integer, range: 0..9, default: 6,
|
|
32
|
+
# cli: "--zlib-level", desc: "zlib compression level"
|
|
33
|
+
# option :uncompressed, type: :boolean, default: false,
|
|
34
|
+
# cli: "--uncompressed", desc: "store tables uncompressed"
|
|
33
35
|
#
|
|
34
|
-
# def
|
|
35
|
-
#
|
|
36
|
-
#
|
|
36
|
+
# def convert(font, options = {})
|
|
37
|
+
# self.class.validate_options!(options)
|
|
38
|
+
# # ...
|
|
37
39
|
# end
|
|
38
40
|
# end
|
|
39
41
|
module ConversionStrategy
|
|
40
|
-
#
|
|
42
|
+
# Declarative description of a single strategy option.
|
|
43
|
+
# `allowed_values` is spelled out (not `values`) to avoid shadowing
|
|
44
|
+
# Struct#values.
|
|
45
|
+
Option = Struct.new(:name, :type, :default, :cli, :desc, :range,
|
|
46
|
+
:allowed_values, keyword_init: true)
|
|
47
|
+
|
|
48
|
+
# Class methods mixed into including classes via `included`.
|
|
49
|
+
module ClassMethods
|
|
50
|
+
# Declare an option this strategy accepts.
|
|
51
|
+
#
|
|
52
|
+
# @param name [Symbol] Option name (the hash key used in `convert`)
|
|
53
|
+
# @param type [Symbol] One of :integer, :boolean, :string
|
|
54
|
+
# @param default [Object] Default value when the caller omits the option
|
|
55
|
+
# @param cli [String] CLI flag shape (for help text generation)
|
|
56
|
+
# @param desc [String] Human-readable description
|
|
57
|
+
# @param range [Range, nil] For :integer; valid range
|
|
58
|
+
# @param values [Array, nil] For :string; allowed values
|
|
59
|
+
# @return [void]
|
|
60
|
+
def option(name, type:, default:, cli:, desc:, range: nil, values: nil)
|
|
61
|
+
declared_options << Option.new(
|
|
62
|
+
name: name, type: type, default: default, cli: cli, desc: desc,
|
|
63
|
+
range: range, allowed_values: values
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# All options declared by this class.
|
|
68
|
+
#
|
|
69
|
+
# @return [Array<Option>]
|
|
70
|
+
def declared_options
|
|
71
|
+
@declared_options ||= []
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Public accessor: the full list of options for this strategy.
|
|
75
|
+
alias supported_options declared_options
|
|
76
|
+
|
|
77
|
+
# Find the option schema for a given key (symbol or string).
|
|
78
|
+
#
|
|
79
|
+
# @param name [Symbol, String]
|
|
80
|
+
# @return [Option, nil]
|
|
81
|
+
def option_for(name)
|
|
82
|
+
supported_options.find { |o| o.name == name.to_sym }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Default values for every declared option.
|
|
86
|
+
#
|
|
87
|
+
# @return [Hash{Symbol => Object}]
|
|
88
|
+
def default_options
|
|
89
|
+
supported_options.to_h { |o| [o.name, o.default] }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Validate a user-provided options hash against this strategy's schema.
|
|
93
|
+
#
|
|
94
|
+
# Raises ArgumentError for any unknown key, wrong type, or
|
|
95
|
+
# out-of-range value. Called by FormatConverter after strategy
|
|
96
|
+
# selection, so cross-format misuse (e.g., `--zlib-level` on a
|
|
97
|
+
# WOFF2 conversion) is caught here.
|
|
98
|
+
#
|
|
99
|
+
# @param user_options [Hash{Symbol, String => Object}]
|
|
100
|
+
# @return [void]
|
|
101
|
+
# @raise [ArgumentError] if any key is unknown or any value is invalid
|
|
102
|
+
def validate_options!(user_options)
|
|
103
|
+
user_options.each_key do |key|
|
|
104
|
+
opt = option_for(key)
|
|
105
|
+
next if opt
|
|
106
|
+
|
|
107
|
+
names = supported_options.map(&:name)
|
|
108
|
+
list = names.empty? ? "(none)" : names.join(", ")
|
|
109
|
+
raise ArgumentError,
|
|
110
|
+
"Unknown option #{key.inspect} for #{name}. " \
|
|
111
|
+
"Supported: #{list}"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
user_options.each do |key, value|
|
|
115
|
+
opt = option_for(key)
|
|
116
|
+
validate_option_value!(opt, value) unless value.nil?
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
# Type-check a single value against its declared schema.
|
|
123
|
+
#
|
|
124
|
+
# @param opt [Option]
|
|
125
|
+
# @param value [Object]
|
|
126
|
+
# @return [void]
|
|
127
|
+
# @raise [ArgumentError] if value fails type or range/values check
|
|
128
|
+
def validate_option_value!(opt, value)
|
|
129
|
+
case opt.type
|
|
130
|
+
when :integer
|
|
131
|
+
unless value.is_a?(Integer)
|
|
132
|
+
raise ArgumentError,
|
|
133
|
+
"#{opt.name} must be an Integer, got #{value.inspect} " \
|
|
134
|
+
"(#{value.class})"
|
|
135
|
+
end
|
|
136
|
+
return unless opt.range && !opt.range.cover?(value)
|
|
137
|
+
|
|
138
|
+
raise ArgumentError,
|
|
139
|
+
"#{opt.name} must be in #{opt.range}, got #{value}"
|
|
140
|
+
when :boolean
|
|
141
|
+
return if [true, false].include?(value)
|
|
142
|
+
|
|
143
|
+
raise ArgumentError,
|
|
144
|
+
"#{opt.name} must be true or false, got #{value.inspect}"
|
|
145
|
+
when :string
|
|
146
|
+
unless value.is_a?(String)
|
|
147
|
+
raise ArgumentError,
|
|
148
|
+
"#{opt.name} must be a String, got #{value.class}"
|
|
149
|
+
end
|
|
150
|
+
return unless opt.allowed_values && !opt.allowed_values.include?(value)
|
|
151
|
+
|
|
152
|
+
raise ArgumentError,
|
|
153
|
+
"#{opt.name} must be one of #{opt.allowed_values.join(', ')}, " \
|
|
154
|
+
"got #{value.inspect}"
|
|
155
|
+
else
|
|
156
|
+
raise "Unknown option type #{opt.type.inspect} on #{opt.name}"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Mix ClassMethods into any class that includes this module.
|
|
162
|
+
def self.included(base)
|
|
163
|
+
base.extend(ClassMethods)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Convert font to target format.
|
|
41
167
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
168
|
+
# Strategies must implement this. Subclasses should call
|
|
169
|
+
# `self.class.validate_options!(options)` first to enforce their schema.
|
|
44
170
|
#
|
|
45
171
|
# @param font [TrueTypeFont, OpenTypeFont] Source font
|
|
46
172
|
# @param options [Hash] Conversion options
|
|
@@ -51,30 +177,19 @@ module Fontisan
|
|
|
51
177
|
"#{self.class.name} must implement convert(font, options)"
|
|
52
178
|
end
|
|
53
179
|
|
|
54
|
-
# Get list of supported conversions
|
|
55
|
-
#
|
|
56
|
-
# Returns an array of [source_format, target_format] pairs that
|
|
57
|
-
# this strategy can handle.
|
|
180
|
+
# Get list of supported conversions.
|
|
58
181
|
#
|
|
59
|
-
# @return [Array<Array<Symbol>>] Supported
|
|
182
|
+
# @return [Array<Array<Symbol>>] Supported [source, target] pairs
|
|
60
183
|
# @raise [NotImplementedError] If not implemented by strategy
|
|
61
|
-
#
|
|
62
|
-
# @example
|
|
63
|
-
# strategy.supported_conversions
|
|
64
|
-
# # => [[:ttf, :otf], [:otf, :ttf]]
|
|
65
184
|
def supported_conversions
|
|
66
185
|
raise NotImplementedError,
|
|
67
186
|
"#{self.class.name} must implement supported_conversions"
|
|
68
187
|
end
|
|
69
188
|
|
|
70
|
-
# Validate that conversion is possible
|
|
71
|
-
#
|
|
72
|
-
# Checks if the given font can be converted to the target format.
|
|
73
|
-
# Should raise an error with a clear message if conversion is not
|
|
74
|
-
# possible.
|
|
189
|
+
# Validate that conversion is possible.
|
|
75
190
|
#
|
|
76
191
|
# @param font [TrueTypeFont, OpenTypeFont] Font to validate
|
|
77
|
-
# @param target_format [Symbol] Target format
|
|
192
|
+
# @param target_format [Symbol] Target format
|
|
78
193
|
# @return [Boolean] True if valid
|
|
79
194
|
# @raise [Error] If conversion is not possible
|
|
80
195
|
# @raise [NotImplementedError] If not implemented by strategy
|
|
@@ -83,11 +198,11 @@ module Fontisan
|
|
|
83
198
|
"#{self.class.name} must implement validate(font, target_format)"
|
|
84
199
|
end
|
|
85
200
|
|
|
86
|
-
# Check if strategy supports a conversion
|
|
201
|
+
# Check if strategy supports a given conversion.
|
|
87
202
|
#
|
|
88
|
-
# @param source_format [Symbol]
|
|
89
|
-
# @param target_format [Symbol]
|
|
90
|
-
# @return [Boolean]
|
|
203
|
+
# @param source_format [Symbol]
|
|
204
|
+
# @param target_format [Symbol]
|
|
205
|
+
# @return [Boolean]
|
|
91
206
|
def supports?(source_format, target_format)
|
|
92
207
|
supported_conversions.include?([source_format, target_format])
|
|
93
208
|
end
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "conversion_strategy"
|
|
4
|
-
require_relative "table_copier"
|
|
5
|
-
require_relative "outline_converter"
|
|
6
|
-
require_relative "woff_writer"
|
|
7
|
-
require_relative "woff2_encoder"
|
|
8
|
-
require_relative "svg_generator"
|
|
9
|
-
require_relative "type1_converter"
|
|
10
3
|
require "yaml"
|
|
11
4
|
|
|
12
5
|
module Fontisan
|
|
@@ -17,18 +10,14 @@ module Fontisan
|
|
|
17
10
|
# primary entry point for all format conversion operations. It:
|
|
18
11
|
# - Selects appropriate conversion strategy based on source/target formats
|
|
19
12
|
# - Validates conversions against the conversion matrix
|
|
13
|
+
# - Validates user-supplied options against the selected strategy's schema
|
|
20
14
|
# - Delegates actual conversion to strategy implementations
|
|
21
15
|
# - Provides clean error messages for unsupported conversions
|
|
22
16
|
#
|
|
23
17
|
# The converter uses a strategy pattern with pluggable strategies for
|
|
24
|
-
# different conversion types
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# - Woff2Encoder: TTF/OTF → WOFF2 compression
|
|
28
|
-
# - SvgGenerator: TTF/OTF → SVG font generation
|
|
29
|
-
#
|
|
30
|
-
# Supported conversions are defined in the conversion matrix configuration
|
|
31
|
-
# file, making it easy to extend without modifying code.
|
|
18
|
+
# different conversion types. Each strategy declares its own options via
|
|
19
|
+
# the `ConversionStrategy.option` DSL; the converter enforces the
|
|
20
|
+
# format ↔ option mapping at runtime.
|
|
32
21
|
#
|
|
33
22
|
# @example Converting TTF to OTF
|
|
34
23
|
# converter = Fontisan::Converters::FormatConverter.new
|
|
@@ -41,6 +30,81 @@ module Fontisan
|
|
|
41
30
|
# tables = converter.convert(font, :ttf) # TTF to TTF
|
|
42
31
|
# FontWriter.write_to_file(tables, 'copy.ttf')
|
|
43
32
|
class FormatConverter
|
|
33
|
+
# Registry of all strategy classes. Single source of truth for option
|
|
34
|
+
# discovery and strategy lookup. Add a new format by appending its
|
|
35
|
+
# strategy class here.
|
|
36
|
+
STRATEGY_CLASSES = [
|
|
37
|
+
TableCopier,
|
|
38
|
+
OutlineConverter,
|
|
39
|
+
Type1Converter,
|
|
40
|
+
WoffWriter,
|
|
41
|
+
Woff2Encoder,
|
|
42
|
+
SvgGenerator,
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
class << self
|
|
46
|
+
# All option names declared by any strategy. Used by ConversionOptions
|
|
47
|
+
# to keep its generating-options list in sync without duplicating the
|
|
48
|
+
# schema.
|
|
49
|
+
#
|
|
50
|
+
# @return [Array<Symbol>]
|
|
51
|
+
def all_strategy_option_names
|
|
52
|
+
STRATEGY_CLASSES.flat_map { |k| k.supported_options.map(&:name) }.uniq
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Look up the strategy class that handles a given conversion.
|
|
56
|
+
#
|
|
57
|
+
# @param source_format [Symbol]
|
|
58
|
+
# @param target_format [Symbol]
|
|
59
|
+
# @return [Class, nil]
|
|
60
|
+
def strategy_class_for(source_format, target_format)
|
|
61
|
+
STRATEGY_CLASSES.find do |klass|
|
|
62
|
+
klass.new.supports?(source_format, target_format)
|
|
63
|
+
rescue NotImplementedError
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Strategies whose supported_conversions include the given target.
|
|
69
|
+
#
|
|
70
|
+
# @param target_format [Symbol]
|
|
71
|
+
# @return [Array[Class]]
|
|
72
|
+
def strategies_for_target(target_format)
|
|
73
|
+
STRATEGY_CLASSES.select do |klass|
|
|
74
|
+
klass.new.supported_conversions.any? { |(_, t)| t == target_format }
|
|
75
|
+
rescue NotImplementedError
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Cross-format option check, independent of source format. Used by
|
|
81
|
+
# OutputWriter (which doesn't know the source format at write time)
|
|
82
|
+
# to catch e.g. `--brotli-quality` passed with `--to woff`.
|
|
83
|
+
#
|
|
84
|
+
# @param target_format [Symbol]
|
|
85
|
+
# @param options [Hash]
|
|
86
|
+
# @return [void]
|
|
87
|
+
# @raise [ArgumentError] if a user-supplied option is declared only by
|
|
88
|
+
# strategies that don't handle this target
|
|
89
|
+
def validate_options_for_target!(target_format, options)
|
|
90
|
+
handlers = strategies_for_target(target_format)
|
|
91
|
+
handler_names = handlers.flat_map do |k|
|
|
92
|
+
k.supported_options.map(&:name)
|
|
93
|
+
end.to_set
|
|
94
|
+
non_handler_names = (STRATEGY_CLASSES - handlers)
|
|
95
|
+
.flat_map { |k| k.supported_options.map(&:name) }
|
|
96
|
+
|
|
97
|
+
conflicts = options.keys.select do |k|
|
|
98
|
+
non_handler_names.include?(k.to_sym)
|
|
99
|
+
end
|
|
100
|
+
return if conflicts.empty?
|
|
101
|
+
|
|
102
|
+
accepted = handler_names.empty? ? "(none)" : handler_names.join(", ")
|
|
103
|
+
raise ArgumentError,
|
|
104
|
+
"Option(s) #{conflicts.map(&:inspect).join(', ')} do not apply " \
|
|
105
|
+
"to --to #{target_format}. Accepted for #{target_format}: #{accepted}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
44
108
|
# @return [Hash] Conversion matrix loaded from config
|
|
45
109
|
attr_reader :conversion_matrix
|
|
46
110
|
|
|
@@ -52,15 +116,7 @@ module Fontisan
|
|
|
52
116
|
# @param conversion_matrix_path [String, nil] Path to conversion matrix
|
|
53
117
|
# config. If nil, uses default.
|
|
54
118
|
def initialize(conversion_matrix_path: nil)
|
|
55
|
-
@strategies =
|
|
56
|
-
TableCopier.new,
|
|
57
|
-
OutlineConverter.new,
|
|
58
|
-
Type1Converter.new,
|
|
59
|
-
WoffWriter.new,
|
|
60
|
-
Woff2Encoder.new,
|
|
61
|
-
SvgGenerator.new,
|
|
62
|
-
]
|
|
63
|
-
|
|
119
|
+
@strategies = self.class::STRATEGY_CLASSES.map(&:new)
|
|
64
120
|
load_conversion_matrix(conversion_matrix_path)
|
|
65
121
|
end
|
|
66
122
|
|
|
@@ -105,8 +161,20 @@ module Fontisan
|
|
|
105
161
|
end
|
|
106
162
|
|
|
107
163
|
strategy = select_strategy(source_format, target_format)
|
|
108
|
-
|
|
109
|
-
|
|
164
|
+
|
|
165
|
+
# Enforce format ↔ option mapping at the orchestrator level so each
|
|
166
|
+
# strategy only sees options it declared. Cross-format misuse
|
|
167
|
+
# (e.g., `--zlib-level` on a WOFF2 conversion) raises here with a
|
|
168
|
+
# clear message; the strategy itself never has to defensively
|
|
169
|
+
# ignore unknown keys.
|
|
170
|
+
validate_strategy_options!(strategy, source_format, target_format,
|
|
171
|
+
options)
|
|
172
|
+
sliced = slice_strategy_options(options, strategy)
|
|
173
|
+
|
|
174
|
+
tables = strategy.convert(
|
|
175
|
+
font,
|
|
176
|
+
sliced.merge(target_format: target_format),
|
|
177
|
+
)
|
|
110
178
|
|
|
111
179
|
# Preserve variation data if requested and font is variable
|
|
112
180
|
if options.fetch(:preserve_variation, true) && variable_font?(font)
|
|
@@ -178,8 +246,6 @@ module Fontisan
|
|
|
178
246
|
# @option options [Integer] :instance_index Named instance index
|
|
179
247
|
# @return [Hash] Hash with :svg_xml key
|
|
180
248
|
def convert_variable_to_svg(font, options = {})
|
|
181
|
-
require_relative "../variation/variable_svg_generator"
|
|
182
|
-
|
|
183
249
|
coordinates = options[:instance_coordinates] || {}
|
|
184
250
|
generator = Variation::VariableSvgGenerator.new(font, coordinates)
|
|
185
251
|
|
|
@@ -214,7 +280,6 @@ module Fontisan
|
|
|
214
280
|
options)
|
|
215
281
|
# Case 1: Compatible formats (same outline format) - just copy tables
|
|
216
282
|
if compatible_variation_formats?(source_format, target_format)
|
|
217
|
-
require_relative "../variation/variation_preserver"
|
|
218
283
|
Variation::VariationPreserver.preserve(font, tables, options)
|
|
219
284
|
|
|
220
285
|
# Case 2: Different outline formats - convert variation data
|
|
@@ -278,9 +343,6 @@ options)
|
|
|
278
343
|
# @return [Hash<String, String>] Tables with converted variation
|
|
279
344
|
def convert_variation_data(font, tables, source_format, target_format,
|
|
280
345
|
_options)
|
|
281
|
-
require_relative "../variation/variation_preserver"
|
|
282
|
-
require_relative "../variation/converter"
|
|
283
|
-
|
|
284
346
|
# For now, just preserve common tables and warn about conversion
|
|
285
347
|
warn "WARNING: Full variation conversion (#{source_format} → " \
|
|
286
348
|
"#{target_format}) not yet implemented. " \
|
|
@@ -420,6 +482,55 @@ _options)
|
|
|
420
482
|
"Cannot detect font format: missing both CFF and glyf tables"
|
|
421
483
|
end
|
|
422
484
|
end
|
|
485
|
+
|
|
486
|
+
# Cross-format option check. Any user-supplied key that belongs to
|
|
487
|
+
# another strategy (i.e., is valid for some other format) raises
|
|
488
|
+
# immediately — this is what makes `--zlib-level --to woff2` fail
|
|
489
|
+
# predictably.
|
|
490
|
+
#
|
|
491
|
+
# @param strategy [Object] Selected strategy instance
|
|
492
|
+
# @param source_format [Symbol]
|
|
493
|
+
# @param target_format [Symbol]
|
|
494
|
+
# @param options [Hash]
|
|
495
|
+
# @return [void]
|
|
496
|
+
# @raise [ArgumentError] if a user option is declared by another strategy
|
|
497
|
+
# @raise [ArgumentError] if a user option fails type/range validation
|
|
498
|
+
def validate_strategy_options!(strategy, source_format, target_format,
|
|
499
|
+
options)
|
|
500
|
+
this_class = strategy.class
|
|
501
|
+
other_classes = self.class::STRATEGY_CLASSES.reject do |k|
|
|
502
|
+
k == this_class
|
|
503
|
+
end
|
|
504
|
+
other_names = other_classes.flat_map do |k|
|
|
505
|
+
k.supported_options.map(&:name)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
conflicts = options.keys.select do |k|
|
|
509
|
+
other_names.include?(k.to_sym)
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
if conflicts.any?
|
|
513
|
+
accepted = this_class.supported_options.map(&:name)
|
|
514
|
+
accepted_list = accepted.empty? ? "(none)" : accepted.join(", ")
|
|
515
|
+
raise ArgumentError,
|
|
516
|
+
"Option(s) #{conflicts.map(&:inspect).join(', ')} do not apply " \
|
|
517
|
+
"to #{source_format}→#{target_format} " \
|
|
518
|
+
"(#{this_class.name.demodulize}). " \
|
|
519
|
+
"Accepted: #{accepted_list}"
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
this_class.validate_options!(slice_strategy_options(options, strategy))
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
# Slice an options hash to only the keys declared by the given strategy.
|
|
526
|
+
#
|
|
527
|
+
# @param options [Hash]
|
|
528
|
+
# @param strategy [Object]
|
|
529
|
+
# @return [Hash]
|
|
530
|
+
def slice_strategy_options(options, strategy)
|
|
531
|
+
names = strategy.class.supported_options.to_set(&:name)
|
|
532
|
+
options.select { |k, _| names.include?(k.to_sym) }
|
|
533
|
+
end
|
|
423
534
|
end
|
|
424
535
|
end
|
|
425
536
|
end
|
|
@@ -1,24 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../conversion_options"
|
|
4
|
-
require_relative "conversion_strategy"
|
|
5
|
-
require_relative "../outline_extractor"
|
|
6
|
-
require_relative "../models/outline"
|
|
7
|
-
require_relative "../tables/cff/charstring_builder"
|
|
8
|
-
require_relative "outline_extraction"
|
|
9
|
-
require_relative "cff_table_builder"
|
|
10
|
-
require_relative "glyf_table_builder"
|
|
11
|
-
require_relative "outline_optimizer"
|
|
12
|
-
require_relative "../hints/truetype_hint_extractor"
|
|
13
|
-
require_relative "../hints/postscript_hint_extractor"
|
|
14
|
-
require_relative "../hints/hint_converter"
|
|
15
|
-
require_relative "../hints/truetype_hint_applier"
|
|
16
|
-
require_relative "../hints/postscript_hint_applier"
|
|
17
|
-
require_relative "../tables/cff2"
|
|
18
|
-
require_relative "../variation/data_extractor"
|
|
19
|
-
require_relative "../variation/instance_generator"
|
|
20
|
-
require_relative "../variation/converter"
|
|
21
|
-
|
|
22
3
|
module Fontisan
|
|
23
4
|
module Converters
|
|
24
5
|
# Strategy for converting between TTF and OTF outline formats
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../outline_extractor"
|
|
4
|
-
require_relative "../tables/cff/charstring_builder"
|
|
5
|
-
require_relative "../tables/glyf/glyph_builder"
|
|
6
|
-
require_relative "../tables/glyf/compound_glyph_resolver"
|
|
7
|
-
|
|
8
3
|
module Fontisan
|
|
9
4
|
module Converters
|
|
10
5
|
# Extracts all glyph outlines from a font for conversion purposes
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../optimizers/pattern_analyzer"
|
|
4
|
-
require_relative "../optimizers/subroutine_optimizer"
|
|
5
|
-
require_relative "../optimizers/subroutine_builder"
|
|
6
|
-
require_relative "../optimizers/charstring_rewriter"
|
|
7
|
-
|
|
8
3
|
module Fontisan
|
|
9
4
|
module Converters
|
|
10
5
|
# Optimizes CFF CharStrings using subroutine extraction
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../conversion_options"
|
|
4
|
-
require_relative "../type1/charstring_converter"
|
|
5
|
-
require_relative "../type1/cff_to_type1_converter"
|
|
6
|
-
require_relative "../type1/font_dictionary"
|
|
7
|
-
require_relative "../type1/charstrings"
|
|
8
|
-
require_relative "../type1/seac_expander"
|
|
9
|
-
require_relative "../type1_font"
|
|
10
|
-
require_relative "cff_table_builder"
|
|
11
|
-
|
|
12
3
|
module Fontisan
|
|
13
4
|
module Converters
|
|
14
5
|
# Converter for Adobe Type 1 fonts to/from SFNT formats.
|
|
@@ -1054,8 +1045,6 @@ module Fontisan
|
|
|
1054
1045
|
# @param font [Type1Font] Source Type 1 font
|
|
1055
1046
|
# @return [String] cmap table binary data
|
|
1056
1047
|
def build_cmap_table(font)
|
|
1057
|
-
require_relative "../type1/agl"
|
|
1058
|
-
|
|
1059
1048
|
data = (+"").b
|
|
1060
1049
|
|
|
1061
1050
|
# Get encoding from Type1Font
|