stationery 0.9.0 → 0.10.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +143 -34
  4. data/lib/stationery/{svg → css}/selector.rb +1 -1
  5. data/lib/stationery/{svg → css}/stylesheet.rb +20 -6
  6. data/lib/stationery/css.rb +20 -0
  7. data/lib/stationery/document.rb +21 -9
  8. data/lib/stationery/elements/rich.rb +10 -2
  9. data/lib/stationery/elements.rb +9 -4
  10. data/lib/stationery/errors.rb +4 -0
  11. data/lib/stationery/fonts/fallback.rb +1 -1
  12. data/lib/stationery/html/css.rb +276 -0
  13. data/lib/stationery/html/document.rb +5 -3
  14. data/lib/stationery/html/tokenizer.rb +15 -4
  15. data/lib/stationery/html/tree_builder/blocks.rb +90 -40
  16. data/lib/stationery/html/tree_builder/collector.rb +9 -3
  17. data/lib/stationery/html/tree_builder.rb +11 -1
  18. data/lib/stationery/layout/flow.rb +29 -0
  19. data/lib/stationery/layout/image.rb +12 -6
  20. data/lib/stationery/layout/mark.rb +2 -0
  21. data/lib/stationery/layout/node.rb +4 -0
  22. data/lib/stationery/layout/text.rb +47 -10
  23. data/lib/stationery/pdf/assembler.rb +14 -4
  24. data/lib/stationery/pdf/signature/cms.rb +21 -13
  25. data/lib/stationery/pdf/signature/timestamp.rb +120 -0
  26. data/lib/stationery/pdf/signature.rb +16 -9
  27. data/lib/stationery/pdf/writer.rb +73 -19
  28. data/lib/stationery/rich/nodes.rb +37 -11
  29. data/lib/stationery/rich/renderer/boxes.rb +109 -0
  30. data/lib/stationery/rich/renderer/indents.rb +1 -0
  31. data/lib/stationery/rich/renderer/inlines.rb +9 -2
  32. data/lib/stationery/rich/renderer.rb +32 -15
  33. data/lib/stationery/svg/style.rb +4 -6
  34. data/lib/stationery/testing/inspector.rb +49 -6
  35. data/lib/stationery/text/breaks.rb +123 -0
  36. data/lib/stationery/text/paragraph.rb +8 -0
  37. data/lib/stationery/text/runs_builder.rb +4 -0
  38. data/lib/stationery/text/wrapper.rb +57 -8
  39. data/lib/stationery/version.rb +1 -1
  40. data/lib/stationery/warnings.rb +9 -0
  41. data/lib/stationery.rb +3 -2
  42. metadata +8 -3
@@ -3,7 +3,8 @@
3
3
  module Stationery
4
4
  module Text
5
5
  # Greedy line breaking over styled runs. Breaks at spaces (the space is
6
- # dropped at the break) and after hyphens; a word that does not fit is
6
+ # dropped at the break), after hyphens, at a zero-width space (U+200B,
7
+ # HTML's <wbr>) and between ideographic characters (see Breaks); a word that does not fit is
7
8
  # hyphenated when it may be (a soft hyphen U+00AD names the break points,
8
9
  # else the style's `hyphenate` language), and a word wider than the line
9
10
  # is broken between characters. A word that changes style midway
@@ -12,6 +13,7 @@ module Stationery
12
13
  class Wrapper
13
14
  TOKEN = /\n|[ \t]+|[^ \t\n-]*-+|[^ \t\n-]+/
14
15
  SOFT_HYPHEN = "­"
16
+ ZERO_WIDTH_SPACE = Breaks::ZERO_WIDTH_SPACE
15
17
  EPSILON = 0.0001
16
18
 
17
19
  Segment = Data.define(:text, :style)
@@ -34,22 +36,67 @@ module Stationery
34
36
 
35
37
  private
36
38
 
37
- # [:word, segments] | [:space, segments] | [:newline]
39
+ # [:word, segments] | [:space, segments] | [:newline]. A word that runs
40
+ # on into the next styled run stays one word ("<b>Tot</b>al"); a
41
+ # zero-width space is an empty :space, a break that draws nothing; a
42
+ # word with CJK characters is cut into its break units (Breaks).
38
43
  def items(runs)
39
44
  items = []
45
+ @join = false # whether the next token may continue the last word
40
46
  runs.each do |run|
41
- run.text.scan(TOKEN) do |token|
42
- if token == "\n" then items << [:newline]
43
- elsif token.match?(/\A[ \t]/) then items << [:space, [Segment.new(token, run.style)]]
44
- elsif items.last&.first == :word && !items.last.last.last.text.end_with?("-")
45
- items.last.last << Segment.new(token, run.style)
46
- else items << [:word, [Segment.new(token, run.style)]]
47
+ if run.text.include?(ZERO_WIDTH_SPACE)
48
+ run.text.split(ZERO_WIDTH_SPACE, -1).each_with_index do |part, index|
49
+ if index.positive?
50
+ items << [:space, []]
51
+ @join = false
52
+ end
53
+ tokens(items, part, run.style)
47
54
  end
55
+ else
56
+ tokens(items, run.text, run.style)
48
57
  end
49
58
  end
50
59
  items
51
60
  end
52
61
 
62
+ def tokens(items, text, style)
63
+ text.scan(TOKEN) do |token|
64
+ if token == "\n"
65
+ items << [:newline]
66
+ @join = false
67
+ elsif token.match?(/\A[ \t]/)
68
+ items << [:space, [Segment.new(token, style)]]
69
+ @join = false
70
+ else
71
+ word_units(items, token, style)
72
+ end
73
+ end
74
+ end
75
+
76
+ # A Latin word is one unit and may run on into the next styled run
77
+ # unless it ends in a hyphen; a word with CJK characters is cut into
78
+ # its break units, none of which the next token continues. Latin words
79
+ # skip the unit split, so they cost no allocation of their own.
80
+ def word_units(items, token, style)
81
+ if Breaks.cjk?(token)
82
+ Breaks.units(token).each do |text, glued|
83
+ add_unit(items, text, style, glued)
84
+ @join = false
85
+ end
86
+ else
87
+ add_unit(items, token, style, false)
88
+ @join = !token.end_with?("-")
89
+ end
90
+ end
91
+
92
+ def add_unit(items, text, style, glued)
93
+ if (@join || glued) && items.last&.first == :word
94
+ items.last.last << Segment.new(text, style)
95
+ else
96
+ items << [:word, [Segment.new(text, style)]]
97
+ end
98
+ end
99
+
53
100
  def place((kind, segments))
54
101
  @ended_with_newline = kind == :newline
55
102
  case kind
@@ -115,6 +162,8 @@ module Stationery
115
162
  return (1...chars.length).select { |index| chars[index - 1].text == SOFT_HYPHEN } if @explicit
116
163
 
117
164
  text = chars.map(&:text).join
165
+ return [] if Breaks.cjk?(text)
166
+
118
167
  language = chars.first.style.hyphenate or return []
119
168
  core = text[/\p{L}+/] or return []
120
169
  offset = text.index(core)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stationery
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
@@ -47,6 +47,15 @@ module Stationery
47
47
  def message = "content nested #{depth} levels deep was flattened below level #{limit}"
48
48
  end
49
49
 
50
+ UnsupportedCss = Data.define(:properties, :selectors) do
51
+ def message
52
+ parts = []
53
+ parts << "properties #{properties.join(", ")}" if properties.any?
54
+ parts << "selectors #{selectors.join(", ")}" if selectors.any?
55
+ "html styles not read: #{parts.join("; ")}"
56
+ end
57
+ end
58
+
50
59
  DuplicateAnchor = Data.define(:name, :page) do
51
60
  def message = %(anchor "#{name}" on page #{page} is already defined)
52
61
  end
data/lib/stationery.rb CHANGED
@@ -68,6 +68,7 @@ require_relative "stationery/pdf/conformance"
68
68
  require_relative "stationery/pdf/factur_x"
69
69
  require_relative "stationery/pdf/signature"
70
70
  require_relative "stationery/pdf/signature/cms"
71
+ require_relative "stationery/pdf/signature/timestamp"
71
72
  require_relative "stationery/forms/metrics"
72
73
  require_relative "stationery/forms/typeface"
73
74
  require_relative "stationery/forms/field"
@@ -82,6 +83,7 @@ require_relative "stationery/text/entities"
82
83
  require_relative "stationery/text/markup"
83
84
  require_relative "stationery/text/runs_builder"
84
85
  require_relative "stationery/text/line"
86
+ require_relative "stationery/text/breaks"
85
87
  require_relative "stationery/text/wrapper"
86
88
  require_relative "stationery/text/paragraph"
87
89
  require_relative "stationery/layout/node"
@@ -106,8 +108,7 @@ require_relative "stationery/svg/path_data"
106
108
  require_relative "stationery/svg/arc"
107
109
  require_relative "stationery/svg/parser"
108
110
  require_relative "stationery/svg/transform"
109
- require_relative "stationery/svg/selector"
110
- require_relative "stationery/svg/stylesheet"
111
+ require_relative "stationery/css"
111
112
  require_relative "stationery/svg/style"
112
113
  require_relative "stationery/svg/shapes"
113
114
  require_relative "stationery/svg/bounds"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stationery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
@@ -40,6 +40,9 @@ files:
40
40
  - lib/stationery/cli/render.rb
41
41
  - lib/stationery/color.rb
42
42
  - lib/stationery/component.rb
43
+ - lib/stationery/css.rb
44
+ - lib/stationery/css/selector.rb
45
+ - lib/stationery/css/stylesheet.rb
43
46
  - lib/stationery/document.rb
44
47
  - lib/stationery/elements.rb
45
48
  - lib/stationery/elements/forms.rb
@@ -90,6 +93,7 @@ files:
90
93
  - lib/stationery/forms/metrics.rb
91
94
  - lib/stationery/forms/typeface.rb
92
95
  - lib/stationery/geometry.rb
96
+ - lib/stationery/html/css.rb
93
97
  - lib/stationery/html/document.rb
94
98
  - lib/stationery/html/tokenizer.rb
95
99
  - lib/stationery/html/tree_builder.rb
@@ -161,6 +165,7 @@ files:
161
165
  - lib/stationery/pdf/serializer.rb
162
166
  - lib/stationery/pdf/signature.rb
163
167
  - lib/stationery/pdf/signature/cms.rb
168
+ - lib/stationery/pdf/signature/timestamp.rb
164
169
  - lib/stationery/pdf/stream.rb
165
170
  - lib/stationery/pdf/types.rb
166
171
  - lib/stationery/pdf/writer.rb
@@ -174,6 +179,7 @@ files:
174
179
  - lib/stationery/rich/nesting.rb
175
180
  - lib/stationery/rich/nodes.rb
176
181
  - lib/stationery/rich/renderer.rb
182
+ - lib/stationery/rich/renderer/boxes.rb
177
183
  - lib/stationery/rich/renderer/indents.rb
178
184
  - lib/stationery/rich/renderer/inlines.rb
179
185
  - lib/stationery/rich/renderer/links.rb
@@ -189,11 +195,9 @@ files:
189
195
  - lib/stationery/svg/parser.rb
190
196
  - lib/stationery/svg/path_data.rb
191
197
  - lib/stationery/svg/region.rb
192
- - lib/stationery/svg/selector.rb
193
198
  - lib/stationery/svg/shading.rb
194
199
  - lib/stationery/svg/shapes.rb
195
200
  - lib/stationery/svg/style.rb
196
- - lib/stationery/svg/stylesheet.rb
197
201
  - lib/stationery/svg/text.rb
198
202
  - lib/stationery/svg/transform.rb
199
203
  - lib/stationery/svg/viewport.rb
@@ -205,6 +209,7 @@ files:
205
209
  - lib/stationery/testing/marked_text.rb
206
210
  - lib/stationery/testing/matchers.rb
207
211
  - lib/stationery/testing/structure_reader.rb
212
+ - lib/stationery/text/breaks.rb
208
213
  - lib/stationery/text/entities.rb
209
214
  - lib/stationery/text/entities/html4.rb
210
215
  - lib/stationery/text/line.rb