stationery 0.6.0 → 0.7.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/CHANGELOG.md +10 -0
- data/README.md +72 -15
- data/lib/stationery/builder.rb +5 -3
- data/lib/stationery/canvas/text.rb +4 -3
- data/lib/stationery/canvas.rb +5 -2
- data/lib/stationery/document.rb +26 -9
- data/lib/stationery/elements.rb +1 -1
- data/lib/stationery/fonts/fallback.rb +3 -3
- data/lib/stationery/fonts/font.rb +39 -21
- data/lib/stationery/fonts/gsub/single_subst.rb +37 -0
- data/lib/stationery/fonts/gsub.rb +65 -20
- data/lib/stationery/fonts/ligatures.rb +6 -4
- data/lib/stationery/hyphenation/patterns/LICENSES.md +60 -0
- data/lib/stationery/hyphenation/patterns/de-1996.pat.txt +36709 -0
- data/lib/stationery/hyphenation/patterns/en-us.hyp.txt +14 -0
- data/lib/stationery/hyphenation/patterns/en-us.pat.txt +4938 -0
- data/lib/stationery/hyphenation/patterns/sv.pat.txt +4693 -0
- data/lib/stationery/hyphenation.rb +132 -0
- data/lib/stationery/images/png.rb +66 -0
- data/lib/stationery/images/resampled.rb +80 -0
- data/lib/stationery/layout/image.rb +28 -2
- data/lib/stationery/layout/paginator.rb +1 -1
- data/lib/stationery/layout/text.rb +2 -2
- data/lib/stationery/minitest.rb +5 -0
- data/lib/stationery/page_templates.rb +2 -1
- data/lib/stationery/pdf/assembler.rb +6 -2
- data/lib/stationery/pdf/page_labels.rb +71 -0
- data/lib/stationery/testing/inspector.rb +13 -0
- data/lib/stationery/testing/matchers.rb +10 -0
- data/lib/stationery/text/entities.rb +14 -4
- data/lib/stationery/text/paragraph.rb +1 -1
- data/lib/stationery/text/style.rb +14 -3
- data/lib/stationery/text/wrapper.rb +73 -12
- data/lib/stationery/version.rb +1 -1
- data/lib/stationery/warnings.rb +6 -0
- data/lib/stationery.rb +4 -0
- metadata +10 -1
|
@@ -2,51 +2,96 @@
|
|
|
2
2
|
|
|
3
3
|
module Stationery
|
|
4
4
|
module Fonts
|
|
5
|
-
#
|
|
6
|
-
# (
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# Glyph substitution from the font's GSUB table: every feature's
|
|
6
|
+
# SingleSubst (type 1) and LigatureSubst (type 4) lookups, directly or
|
|
7
|
+
# behind Extension lookups. `liga` gives the standard ligatures; `smcp`,
|
|
8
|
+
# `onum`, `tnum`, `dlig`, `ss01` and the rest are applied on request.
|
|
9
|
+
# Contextual lookups (types 5, 6 and 8) are not read, so `calt` and
|
|
10
|
+
# `clig` do nothing. Scripts, languages and lookup flags are not
|
|
11
|
+
# distinguished.
|
|
9
12
|
class Gsub
|
|
13
|
+
SINGLE = 1
|
|
10
14
|
LIGATURE = 4
|
|
11
15
|
EXTENSION = 7
|
|
16
|
+
LIGA = ["liga"].freeze
|
|
12
17
|
|
|
13
|
-
# nil when the font has no GSUB table or no
|
|
18
|
+
# nil when the font has no GSUB table, an unknown version, or no lookup
|
|
19
|
+
# of a supported type behind any feature.
|
|
14
20
|
def self.parse(ttf)
|
|
15
21
|
base = ttf.table_offset("GSUB")
|
|
16
22
|
return unless base && ttf.u16(base) == 1
|
|
17
23
|
|
|
18
|
-
lookups =
|
|
19
|
-
|
|
24
|
+
lookups = {}
|
|
25
|
+
features = feature_indices(ttf, base + ttf.u16(base + 6)).transform_values do |indices|
|
|
26
|
+
indices.filter_map do |i|
|
|
27
|
+
subtables = lookups[i] ||= lookup(ttf, base + ttf.u16(base + 8), i)
|
|
28
|
+
[i, subtables] unless subtables.empty?
|
|
29
|
+
end.freeze
|
|
30
|
+
end
|
|
31
|
+
features.reject! { |_, lookups_for| lookups_for.empty? }
|
|
32
|
+
new(features) if features.any?
|
|
20
33
|
end
|
|
21
34
|
|
|
22
|
-
#
|
|
23
|
-
|
|
35
|
+
# { tag => [lookup index, ...] } from the FeatureList, every record of a
|
|
36
|
+
# tag merged, in LookupList order.
|
|
37
|
+
def self.feature_indices(ttf, list)
|
|
38
|
+
Array.new(ttf.u16(list)) { |i| list + 2 + (i * 6) }.each_with_object({}) do |record, features|
|
|
39
|
+
tag = ttf.data.byteslice(record, 4)
|
|
40
|
+
feature = list + ttf.u16(record + 4)
|
|
41
|
+
indices = Array.new(ttf.u16(feature + 2)) { |j| ttf.u16(feature + 4 + (j * 2)) }
|
|
42
|
+
features[tag] = ((features[tag] || []) | indices).sort
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
private_class_method :feature_indices
|
|
46
|
+
|
|
47
|
+
# The `index`th lookup's supported subtables; other types have none.
|
|
48
|
+
def self.lookup(ttf, list, index)
|
|
49
|
+
offset = list + ttf.u16(list + 2 + (index * 2))
|
|
24
50
|
type = ttf.u16(offset)
|
|
25
51
|
subtables = Array.new(ttf.u16(offset + 4)) { |i| offset + ttf.u16(offset + 6 + (i * 2)) }
|
|
26
52
|
subtables.filter_map do |subtable|
|
|
27
|
-
if type ==
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
53
|
+
if type == EXTENSION
|
|
54
|
+
read(ttf.u16(subtable + 2), ttf, subtable + ttf.u32(subtable + 4))
|
|
55
|
+
else
|
|
56
|
+
read(type, ttf, subtable)
|
|
31
57
|
end
|
|
32
58
|
end.freeze
|
|
33
59
|
end
|
|
34
60
|
private_class_method :lookup
|
|
35
61
|
|
|
36
|
-
def
|
|
37
|
-
|
|
62
|
+
def self.read(type, ttf, offset)
|
|
63
|
+
case type
|
|
64
|
+
when SINGLE then SingleSubst.read(ttf, offset)
|
|
65
|
+
when LIGATURE then LigatureSubst.read(ttf, offset)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
private_class_method :read
|
|
69
|
+
|
|
70
|
+
def initialize(features)
|
|
71
|
+
@features = features.freeze
|
|
72
|
+
@plans = {}
|
|
38
73
|
freeze
|
|
39
74
|
end
|
|
40
75
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
76
|
+
# The feature tags this font can apply, e.g. ["liga", "onum", "tnum"].
|
|
77
|
+
def features = @features.keys
|
|
78
|
+
|
|
79
|
+
# [[gid, number of source glyphs it stands for], ...] after applying the
|
|
80
|
+
# lookups of `tags` (feature tag Strings) in LookupList order, each once.
|
|
81
|
+
# Within a lookup the first subtable matching at a position wins and its
|
|
82
|
+
# glyph is not matched again by that lookup.
|
|
83
|
+
def substitute(gids, tags = LIGA)
|
|
84
|
+
plan(tags).reduce(gids.map { |gid| [gid, 1] }) { |glyphs, subtables| apply(subtables, glyphs) }
|
|
46
85
|
end
|
|
47
86
|
|
|
48
87
|
private
|
|
49
88
|
|
|
89
|
+
# The lookups the tags name, merged and ordered; remembered per tag list.
|
|
90
|
+
def plan(tags)
|
|
91
|
+
@plans[tags] ||= tags.flat_map { |tag| @features[tag] || [] }.uniq(&:first).sort_by(&:first)
|
|
92
|
+
.map(&:last).freeze
|
|
93
|
+
end
|
|
94
|
+
|
|
50
95
|
def apply(subtables, glyphs)
|
|
51
96
|
ids = glyphs.map(&:first)
|
|
52
97
|
result = []
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Stationery
|
|
4
4
|
module Fonts
|
|
5
|
-
# Chooses where a font's
|
|
6
|
-
# `substitute(gids)` with [[gid, source glyph
|
|
5
|
+
# Chooses where a font's glyph substitutions come from. Every source
|
|
6
|
+
# answers `substitute(gids, feature_tags)` with [[gid, source glyph
|
|
7
|
+
# count], ...] and `features` with the tags it can apply.
|
|
7
8
|
module Ligatures
|
|
8
|
-
# For fonts without
|
|
9
|
+
# For fonts without a usable GSUB table: every glyph stands for itself.
|
|
9
10
|
module NONE
|
|
10
|
-
def self.substitute(gids) = gids.map { |gid| [gid, 1] }
|
|
11
|
+
def self.substitute(gids, _tags = Gsub::LIGA) = gids.map { |gid| [gid, 1] }
|
|
12
|
+
def self.features = []
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def self.for(ttf) = Gsub.parse(ttf) || NONE
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Hyphenation patterns
|
|
2
|
+
|
|
3
|
+
The `*.pat.txt` and `*.hyp.txt` files in this directory are the plain-text
|
|
4
|
+
(UTF-8) pattern and exception lists from the TeX `hyph-utf8` package
|
|
5
|
+
(https://github.com/hyphenation/tex-hyphen, `hyph-utf8/tex/generic/hyph-utf8/patterns/txt/`),
|
|
6
|
+
unmodified. Each file's own copyright and licence follow, copied from the header
|
|
7
|
+
of its `.tex` source in the same package. The Ruby code that reads them
|
|
8
|
+
(`lib/stationery/hyphenation.rb`) is stationery's and under stationery's licence.
|
|
9
|
+
|
|
10
|
+
## en-us.pat.txt, en-us.hyp.txt — Hyphenation patterns for American English
|
|
11
|
+
|
|
12
|
+
Copyright (C) 1990, 2004, 2005 Gerard D.C. Kuiken. Source: `hyph-en-us.tex`
|
|
13
|
+
(`ushyphmax.tex`, version 2005-05-30). Based on Liang's patterns and the
|
|
14
|
+
Hyphenation Exception Log published in TUGboat, Volume 10 (1989), No. 3.
|
|
15
|
+
|
|
16
|
+
> Copying and distribution of this file, with or without modification, are
|
|
17
|
+
> permitted in any medium without royalty provided the copyright notice and
|
|
18
|
+
> this notice are preserved.
|
|
19
|
+
|
|
20
|
+
Typesetting minimums: 2 letters before a break, 3 after.
|
|
21
|
+
|
|
22
|
+
## de-1996.pat.txt — German Hyphenation Patterns (Reformed Orthography, 2006)
|
|
23
|
+
|
|
24
|
+
TeX-Trennmuster für die reformierte (2006) deutsche Rechtschreibung, version
|
|
25
|
+
2024-02-28, by the Deutschsprachige Trennmustermannschaft (trennmuster@dante.de).
|
|
26
|
+
Copyright (c) 2013-2024 Stephan Hennig, Werner Lemberg, Günter Milde, Sander van
|
|
27
|
+
Geloven, Georg Pfeiffer, Gisbert W. Selke, Tobias Wendorf, Keno Wehr. Source:
|
|
28
|
+
`hyph-de-1996.tex`; generated from
|
|
29
|
+
https://repo.or.cz/w/wortliste.git?a=commit;h=304aaa2188a75e57afe36bad0443d90a9c715b8e.
|
|
30
|
+
Licence: MIT (https://opensource.org/licenses/mit-license.php).
|
|
31
|
+
|
|
32
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33
|
+
> of this software and associated documentation files (the “Software”), to deal
|
|
34
|
+
> in the Software without restriction, including without limitation the rights
|
|
35
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
36
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
37
|
+
> furnished to do so, subject to the following conditions:
|
|
38
|
+
>
|
|
39
|
+
> The above copyright notice and this permission notice shall be included in
|
|
40
|
+
> all copies or substantial portions of the Software.
|
|
41
|
+
>
|
|
42
|
+
> THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
43
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
44
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
45
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
46
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
47
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
48
|
+
> SOFTWARE.
|
|
49
|
+
|
|
50
|
+
Typesetting minimums: 2 letters before a break, 2 after.
|
|
51
|
+
|
|
52
|
+
## sv.pat.txt — Hyphenation patterns for Swedish
|
|
53
|
+
|
|
54
|
+
Copyright (C) 1994 Jan Michael Rynning (jmr (at) incolumitas.se), version
|
|
55
|
+
1994-03-03. Source: `hyph-sv.tex`. Licence: LaTeX Project Public License,
|
|
56
|
+
version 1.2 or later (https://www.latex-project.org/lppl/). This file is
|
|
57
|
+
distributed unmodified, as the "Current Maintainer" released it; the LPPL
|
|
58
|
+
requires that a modified version be renamed and identified as such.
|
|
59
|
+
|
|
60
|
+
Typesetting minimums: 2 letters before a break, 2 after.
|