fontisan 0.4.8 → 0.4.10
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/README.adoc +116 -2
- data/docs/.vitepress/config.ts +1 -0
- data/docs/COLLECTION_VALIDATION.adoc +61 -0
- data/docs/STITCHER_GUIDE.adoc +148 -1
- data/docs/cli/convert.md +44 -2
- data/docs/cli/index.md +19 -3
- data/docs/cli/validate-collection.md +95 -0
- data/docs/cli/validate.md +8 -0
- data/lib/fontisan/converters/svg_generator.rb +30 -82
- data/lib/fontisan/sfnt_font.rb +12 -2
- data/lib/fontisan/stitcher/format_metadata.rb +51 -0
- data/lib/fontisan/stitcher/partition_strategy/base.rb +32 -3
- data/lib/fontisan/stitcher/partition_strategy/by_plane.rb +59 -29
- data/lib/fontisan/stitcher/source.rb +89 -8
- data/lib/fontisan/stitcher.rb +9 -27
- data/lib/fontisan/svg/font_generator.rb +2 -2
- data/lib/fontisan/svg/glyph_generator.rb +44 -9
- data/lib/fontisan/unicode/plane.rb +0 -12
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan.rb +1 -0
- metadata +4 -2
|
@@ -20,7 +20,7 @@ module Fontisan
|
|
|
20
20
|
#
|
|
21
21
|
# @example Generate SVG glyph element
|
|
22
22
|
# generator = GlyphGenerator.new(calculator)
|
|
23
|
-
# xml = generator.generate_glyph_xml(outline,
|
|
23
|
+
# xml = generator.generate_glyph_xml(outline, codepoints: [0x41], advance_width: 600)
|
|
24
24
|
class GlyphGenerator
|
|
25
25
|
# @return [ViewBoxCalculator] Coordinate calculator
|
|
26
26
|
attr_reader :calculator
|
|
@@ -38,23 +38,30 @@ module Fontisan
|
|
|
38
38
|
# Generate SVG glyph element
|
|
39
39
|
#
|
|
40
40
|
# @param outline [Models::GlyphOutline] Glyph outline
|
|
41
|
-
# @param
|
|
42
|
-
#
|
|
41
|
+
# @param codepoints [Array<Integer>] Unicode codepoints that cmap
|
|
42
|
+
# maps to this glyph. Empty for unmapped glyphs (.notdef, raw
|
|
43
|
+
# ligatures, etc.). Each codepoint is rendered per SVG Fonts
|
|
44
|
+
# spec: printable ASCII as the character (XML-escaped), others
|
|
45
|
+
# as &#xHEX; entities. Multiple codepoints are concatenated —
|
|
46
|
+
# rare but valid (e.g. a glyph mapped from both space and
|
|
47
|
+
# non-breaking space).
|
|
48
|
+
# @param glyph_name [String, nil] Glyph name from the post table
|
|
43
49
|
# @param advance_width [Integer] Horizontal advance width
|
|
44
50
|
# @param indent [String] Indentation string
|
|
45
51
|
# @return [String] XML glyph element
|
|
46
|
-
def generate_glyph_xml(outline,
|
|
52
|
+
def generate_glyph_xml(outline, codepoints: [], glyph_name: nil,
|
|
47
53
|
advance_width: 0, indent: " ")
|
|
48
|
-
# Build attribute parts
|
|
49
54
|
attr_parts = []
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
unless codepoints.empty?
|
|
57
|
+
attr_parts << %(unicode="#{format_codepoints(codepoints)}")
|
|
58
|
+
end
|
|
59
|
+
attr_parts << %(glyph-name="#{escape_xml(glyph_name)}") if glyph_name
|
|
60
|
+
attr_parts << %(horiz-adv-x="#{advance_width}") if advance_width&.positive?
|
|
54
61
|
|
|
55
62
|
# Generate SVG path with Y-axis transformation
|
|
56
63
|
path_data = generate_svg_path(outline)
|
|
57
|
-
attr_parts <<
|
|
64
|
+
attr_parts << %(d="#{path_data}") if path_data && !path_data.empty?
|
|
58
65
|
|
|
59
66
|
"#{indent}<glyph #{attr_parts.join(' ')}/>"
|
|
60
67
|
end
|
|
@@ -88,6 +95,34 @@ advance_width: 0, indent: " ")
|
|
|
88
95
|
|
|
89
96
|
private
|
|
90
97
|
|
|
98
|
+
# Format an array of codepoints as the SVG `unicode=` attribute
|
|
99
|
+
# value. Returns the FINAL string — already escaped / entity-fied.
|
|
100
|
+
# The caller must not re-escape it (would double-escape the
|
|
101
|
+
# entities this method emits).
|
|
102
|
+
#
|
|
103
|
+
# Per SVG Fonts spec, each codepoint renders as either:
|
|
104
|
+
# - printable ASCII (0x20..0x7E): the character itself, with
|
|
105
|
+
# XML-special chars (&, <, >, ", ') escaped
|
|
106
|
+
# - any other codepoint: a numeric entity &#xHEX;
|
|
107
|
+
#
|
|
108
|
+
# Multiple codepoints are concatenated in codepoint order. The
|
|
109
|
+
# SVG spec accepts this for ligature-style mappings.
|
|
110
|
+
def format_codepoints(codepoints)
|
|
111
|
+
codepoints.map { |cp| format_codepoint(cp) }.join
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def format_codepoint(cp)
|
|
115
|
+
if printable_ascii?(cp)
|
|
116
|
+
escape_xml(cp.chr(Encoding::UTF_8))
|
|
117
|
+
else
|
|
118
|
+
"&#x#{cp.to_s(16).upcase};"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def printable_ascii?(cp)
|
|
123
|
+
(0x20..0x7E).cover?(cp)
|
|
124
|
+
end
|
|
125
|
+
|
|
91
126
|
# Build SVG path for a contour with Y-axis transformation
|
|
92
127
|
#
|
|
93
128
|
# @param contour [Array<Hash>] Array of point hashes
|
|
@@ -15,18 +15,6 @@ module Fontisan
|
|
|
15
15
|
TIP = 3
|
|
16
16
|
SSP = 14
|
|
17
17
|
|
|
18
|
-
# The handful of mega-blocks large enough to overflow a single
|
|
19
|
-
# plane's 65,535-glyph cap when partitioning by plane. Range +
|
|
20
|
-
# label only — full Unicode Blocks.txt data lives in +Block+
|
|
21
|
-
# (follow-up).
|
|
22
|
-
LARGE_CJK_BLOCKS = {
|
|
23
|
-
"CJK_Ext_B" => 0x2A700..0x2B73F,
|
|
24
|
-
"CJK_Ext_C" => 0x2B740..0x2B81F,
|
|
25
|
-
"CJK_Ext_D" => 0x2B820..0x2CEAF,
|
|
26
|
-
"CJK_Ext_E" => 0x2CEB0..0x2EBEF,
|
|
27
|
-
"CJK_Ext_F" => 0x2EBF0..0x2EE5F,
|
|
28
|
-
}.freeze
|
|
29
|
-
|
|
30
18
|
# @param codepoint [Integer]
|
|
31
19
|
# @return [Integer] plane number (0..16)
|
|
32
20
|
def self.of(codepoint)
|
data/lib/fontisan/version.rb
CHANGED
data/lib/fontisan.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -188,6 +188,7 @@ files:
|
|
|
188
188
|
- docs/cli/subset.md
|
|
189
189
|
- docs/cli/tables.md
|
|
190
190
|
- docs/cli/unicode.md
|
|
191
|
+
- docs/cli/validate-collection.md
|
|
191
192
|
- docs/cli/validate.md
|
|
192
193
|
- docs/cli/variable.md
|
|
193
194
|
- docs/cli/version.md
|
|
@@ -433,6 +434,7 @@ files:
|
|
|
433
434
|
- lib/fontisan/stitcher.rb
|
|
434
435
|
- lib/fontisan/stitcher/collection_result.rb
|
|
435
436
|
- lib/fontisan/stitcher/deduplicator.rb
|
|
437
|
+
- lib/fontisan/stitcher/format_metadata.rb
|
|
436
438
|
- lib/fontisan/stitcher/glyph_limit.rb
|
|
437
439
|
- lib/fontisan/stitcher/glyph_signature.rb
|
|
438
440
|
- lib/fontisan/stitcher/partition_strategy.rb
|