giga-fast-kit 0.0.1

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/giga-fast-kit.gemspec +12 -0
  3. data/prawn-2.5.0/COPYING +2 -0
  4. data/prawn-2.5.0/GPLv2 +339 -0
  5. data/prawn-2.5.0/GPLv3 +674 -0
  6. data/prawn-2.5.0/LICENSE +56 -0
  7. data/prawn-2.5.0/data/fonts/Courier-Bold.afm +342 -0
  8. data/prawn-2.5.0/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/prawn-2.5.0/data/fonts/Courier-Oblique.afm +342 -0
  10. data/prawn-2.5.0/data/fonts/Courier.afm +342 -0
  11. data/prawn-2.5.0/data/fonts/Helvetica-Bold.afm +2827 -0
  12. data/prawn-2.5.0/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  13. data/prawn-2.5.0/data/fonts/Helvetica-Oblique.afm +3051 -0
  14. data/prawn-2.5.0/data/fonts/Helvetica.afm +3051 -0
  15. data/prawn-2.5.0/data/fonts/MustRead.html +19 -0
  16. data/prawn-2.5.0/data/fonts/Symbol.afm +213 -0
  17. data/prawn-2.5.0/data/fonts/Times-Bold.afm +2588 -0
  18. data/prawn-2.5.0/data/fonts/Times-BoldItalic.afm +2384 -0
  19. data/prawn-2.5.0/data/fonts/Times-Italic.afm +2667 -0
  20. data/prawn-2.5.0/data/fonts/Times-Roman.afm +2419 -0
  21. data/prawn-2.5.0/data/fonts/ZapfDingbats.afm +225 -0
  22. data/prawn-2.5.0/lib/prawn/document/bounding_box.rb +625 -0
  23. data/prawn-2.5.0/lib/prawn/document/column_box.rb +177 -0
  24. data/prawn-2.5.0/lib/prawn/document/internals.rb +76 -0
  25. data/prawn-2.5.0/lib/prawn/document/span.rb +65 -0
  26. data/prawn-2.5.0/lib/prawn/document.rb +846 -0
  27. data/prawn-2.5.0/lib/prawn/encoding.rb +85 -0
  28. data/prawn-2.5.0/lib/prawn/errors.rb +73 -0
  29. data/prawn-2.5.0/lib/prawn/font.rb +567 -0
  30. data/prawn-2.5.0/lib/prawn/font_metric_cache.rb +50 -0
  31. data/prawn-2.5.0/lib/prawn/fonts/afm.rb +332 -0
  32. data/prawn-2.5.0/lib/prawn/fonts/dfont.rb +42 -0
  33. data/prawn-2.5.0/lib/prawn/fonts/otf.rb +14 -0
  34. data/prawn-2.5.0/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
  35. data/prawn-2.5.0/lib/prawn/fonts/ttc.rb +41 -0
  36. data/prawn-2.5.0/lib/prawn/fonts/ttf.rb +615 -0
  37. data/prawn-2.5.0/lib/prawn/fonts.rb +14 -0
  38. data/prawn-2.5.0/lib/prawn/graphics/blend_mode.rb +62 -0
  39. data/prawn-2.5.0/lib/prawn/graphics/cap_style.rb +44 -0
  40. data/prawn-2.5.0/lib/prawn/graphics/color.rb +257 -0
  41. data/prawn-2.5.0/lib/prawn/graphics/dash.rb +123 -0
  42. data/prawn-2.5.0/lib/prawn/graphics/join_style.rb +60 -0
  43. data/prawn-2.5.0/lib/prawn/graphics/patterns.rb +389 -0
  44. data/prawn-2.5.0/lib/prawn/graphics/transformation.rb +172 -0
  45. data/prawn-2.5.0/lib/prawn/graphics/transparency.rb +79 -0
  46. data/prawn-2.5.0/lib/prawn/graphics.rb +791 -0
  47. data/prawn-2.5.0/lib/prawn/grid.rb +449 -0
  48. data/prawn-2.5.0/lib/prawn/image_handler.rb +61 -0
  49. data/prawn-2.5.0/lib/prawn/images/image.rb +48 -0
  50. data/prawn-2.5.0/lib/prawn/images/jpg.rb +121 -0
  51. data/prawn-2.5.0/lib/prawn/images/png.rb +383 -0
  52. data/prawn-2.5.0/lib/prawn/images.rb +195 -0
  53. data/prawn-2.5.0/lib/prawn/measurement_extensions.rb +82 -0
  54. data/prawn-2.5.0/lib/prawn/measurements.rb +129 -0
  55. data/prawn-2.5.0/lib/prawn/outline.rb +316 -0
  56. data/prawn-2.5.0/lib/prawn/repeater.rb +140 -0
  57. data/prawn-2.5.0/lib/prawn/security/arcfour.rb +54 -0
  58. data/prawn-2.5.0/lib/prawn/security.rb +308 -0
  59. data/prawn-2.5.0/lib/prawn/soft_mask.rb +105 -0
  60. data/prawn-2.5.0/lib/prawn/stamp.rb +147 -0
  61. data/prawn-2.5.0/lib/prawn/text/box.rb +192 -0
  62. data/prawn-2.5.0/lib/prawn/text/formatted/arranger.rb +396 -0
  63. data/prawn-2.5.0/lib/prawn/text/formatted/box.rb +725 -0
  64. data/prawn-2.5.0/lib/prawn/text/formatted/fragment.rb +373 -0
  65. data/prawn-2.5.0/lib/prawn/text/formatted/line_wrap.rb +335 -0
  66. data/prawn-2.5.0/lib/prawn/text/formatted/parser.rb +284 -0
  67. data/prawn-2.5.0/lib/prawn/text/formatted/wrap.rb +166 -0
  68. data/prawn-2.5.0/lib/prawn/text/formatted.rb +82 -0
  69. data/prawn-2.5.0/lib/prawn/text.rb +701 -0
  70. data/prawn-2.5.0/lib/prawn/transformation_stack.rb +63 -0
  71. data/prawn-2.5.0/lib/prawn/utilities.rb +34 -0
  72. data/prawn-2.5.0/lib/prawn/version.rb +6 -0
  73. data/prawn-2.5.0/lib/prawn/view.rb +116 -0
  74. data/prawn-2.5.0/lib/prawn.rb +83 -0
  75. metadata +114 -0
@@ -0,0 +1,284 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prawn
4
+ module Text
5
+ module Formatted
6
+ # Implements a bi-directional parser between a subset of html and
7
+ # formatted text arrays.
8
+ class Parser
9
+ # @group Extension API
10
+
11
+ # Parser regular expression.
12
+ # @private
13
+ PARSER_REGEX =
14
+ begin
15
+ regex_string =
16
+ "\n|" \
17
+ '<b>|</b>|' \
18
+ '<i>|</i>|' \
19
+ '<u>|</u>|' \
20
+ '<strikethrough>|</strikethrough>|' \
21
+ '<sub>|</sub>|' \
22
+ '<sup>|</sup>|' \
23
+ '<link[^>]*>|</link>|' \
24
+ '<color[^>]*>|</color>|' \
25
+ '<font[^>]*>|</font>|' \
26
+ '<strong>|</strong>|' \
27
+ '<em>|</em>|' \
28
+ '<a[^>]*>|</a>|' \
29
+ "[^<\n]+"
30
+ Regexp.new(regex_string, Regexp::MULTILINE)
31
+ end
32
+
33
+ # Escaped characters.
34
+ # @private
35
+ ESCAPE_CHARS = {
36
+ '&' => '&amp;',
37
+ '>' => '&gt;',
38
+ '<' => '&lt;',
39
+ }.freeze
40
+
41
+ # @private
42
+ UNESCAPE_CHARS = ESCAPE_CHARS.invert.freeze
43
+
44
+ # Parse formatted string.
45
+ #
46
+ # @param string [String]
47
+ # @return [Array<Hash>] Text fragments.
48
+ def self.format(string, *_args)
49
+ tokens = string.gsub(%r{<br\s*/?>}, "\n").scan(PARSER_REGEX)
50
+ array_from_tokens(tokens)
51
+ end
52
+
53
+ # Serialize text fragments to an inline format string.
54
+ #
55
+ # @param array [Array<Hash>]
56
+ # @return [String]
57
+ def self.to_string(array)
58
+ prefixes = {
59
+ bold: '<b>',
60
+ italic: '<i>',
61
+ underline: '<u>',
62
+ strikethrough: '<strikethrough>',
63
+ subscript: '<sub>',
64
+ superscript: '<sup>',
65
+ }
66
+ suffixes = {
67
+ bold: '</b>',
68
+ italic: '</i>',
69
+ underline: '</u>',
70
+ strikethrough: '</strikethrough>',
71
+ subscript: '</sub>',
72
+ superscript: '</sup>',
73
+ }
74
+ array
75
+ .map { |hash|
76
+ prefix = ''
77
+ suffix = ''
78
+ hash[:styles]&.each do |style|
79
+ prefix += prefixes[style]
80
+ suffix = suffixes[style] + suffix
81
+ end
82
+
83
+ font = hash[:font] ? " name='#{hash[:font]}'" : nil
84
+ size = hash[:size] ? " size='#{hash[:size]}'" : nil
85
+ character_spacing =
86
+ if hash[:character_spacing]
87
+ " character_spacing='#{hash[:character_spacing]}'"
88
+ end
89
+ if font || size || character_spacing
90
+ prefix += "<font#{font}#{size}#{character_spacing}>"
91
+ suffix = '</font>'
92
+ end
93
+
94
+ link = hash[:link] ? " href='#{hash[:link]}'" : nil
95
+ anchor = hash[:anchor] ? " anchor='#{hash[:anchor]}'" : nil
96
+ if link || anchor
97
+ prefix += "<link#{link}#{anchor}>"
98
+ suffix = '</link>'
99
+ end
100
+
101
+ if hash[:color]
102
+ prefix +=
103
+ if hash[:color].is_a?(Array)
104
+ "<color c='#{hash[:color][0]}' " \
105
+ "m='#{hash[:color][1]}' " \
106
+ "y='#{hash[:color][2]}' " \
107
+ "k='#{hash[:color][3]}'>"
108
+ else
109
+ "<color rgb='#{hash[:color]}'>"
110
+ end
111
+ suffix = '</color>'
112
+ end
113
+
114
+ string = escape(hash[:text])
115
+ prefix + string + suffix
116
+ }
117
+ .join
118
+ end
119
+
120
+ # Break text into paragraphs.
121
+ #
122
+ # @private
123
+ # @param array [Array<Hash>] Text fragments.
124
+ # @return [Array<Array<Hash>>] Pragraphs of text fragments.
125
+ def self.array_paragraphs(array)
126
+ paragraphs = []
127
+ paragraph = []
128
+ previous_string = "\n"
129
+ scan_pattern = /[^\n]+|\n/
130
+ array.each do |hash|
131
+ hash[:text].scan(scan_pattern).each do |string|
132
+ if string == "\n"
133
+ if previous_string == "\n"
134
+ paragraph << hash.dup.merge(text: "\n")
135
+ end
136
+ paragraphs << paragraph unless paragraph.empty?
137
+ paragraph = []
138
+ else
139
+ paragraph << hash.dup.merge(text: string)
140
+ end
141
+ previous_string = string
142
+ end
143
+ end
144
+ paragraphs << paragraph unless paragraph.empty?
145
+ paragraphs
146
+ end
147
+
148
+ # @private
149
+ # @param tokens [Array<String>]
150
+ # @return [Array<Hash>]
151
+ def self.array_from_tokens(tokens)
152
+ array = []
153
+ styles = []
154
+ colors = []
155
+ link = nil
156
+ anchor = nil
157
+ local = nil
158
+ fonts = []
159
+ sizes = []
160
+ character_spacings = []
161
+
162
+ tokens.each do |token|
163
+ case token
164
+ when '<b>', '<strong>'
165
+ styles << :bold
166
+ when '<i>', '<em>'
167
+ styles << :italic
168
+ when '<u>'
169
+ styles << :underline
170
+ when '<strikethrough>'
171
+ styles << :strikethrough
172
+ when '<sub>'
173
+ styles << :subscript
174
+ when '<sup>'
175
+ styles << :superscript
176
+ when '</b>', '</strong>'
177
+ styles.delete(:bold)
178
+ when '</i>', '</em>'
179
+ styles.delete(:italic)
180
+ when '</u>'
181
+ styles.delete(:underline)
182
+ when '</strikethrough>'
183
+ styles.delete(:strikethrough)
184
+ when '</sub>'
185
+ styles.delete(:subscript)
186
+ when '</sup>'
187
+ styles.delete(:superscript)
188
+ when '</link>', '</a>'
189
+ link = nil
190
+ anchor = nil
191
+ local = nil
192
+ when '</color>'
193
+ colors.pop
194
+ when '</font>'
195
+ fonts.pop
196
+ sizes.pop
197
+ character_spacings.pop
198
+ when /^<link[^>]*>$/, /^<a[^>]*>$/
199
+ matches = /href="([^"]*)"/.match(token) ||
200
+ /href='([^']*)'/.match(token)
201
+ link = matches[1] unless matches.nil?
202
+
203
+ matches = /anchor="([^"]*)"/.match(token) ||
204
+ /anchor='([^']*)'/.match(token)
205
+ anchor = matches[1] unless matches.nil?
206
+
207
+ matches = /local="([^"]*)"/.match(token) ||
208
+ /local='([^']*)'/.match(token)
209
+ local = matches[1] unless matches.nil?
210
+ when /^<color[^>]*>$/
211
+ matches = /rgb="#?([^"]*)"/.match(token) ||
212
+ /rgb='#?([^']*)'/.match(token)
213
+ colors << matches[1] if matches
214
+
215
+ match = /c="#?([^"]*)"/.match(token) ||
216
+ /c='#?([^']*)'/.match(token)
217
+ c = Integer(match[1], 10) unless match.nil?
218
+ match = /m="#?([^"]*)"/.match(token) ||
219
+ /m='#?([^']*)'/.match(token)
220
+ m = Integer(match[1], 10) unless match.nil?
221
+ match = /y="#?([^"]*)"/.match(token) ||
222
+ /y='#?([^']*)'/.match(token)
223
+ y = Integer(match[1], 10) unless match.nil?
224
+ match = /k="#?([^"]*)"/.match(token) ||
225
+ /k='#?([^']*)'/.match(token)
226
+ k = Integer(match[1], 10) unless match.nil?
227
+ colors << [c, m, y, k] if [c, m, y, k].all?
228
+
229
+ # intend to support rgb="#ffffff" or rgb='#ffffff',
230
+ # r="255" g="255" b="255" or r='255' g='255' b='255',
231
+ # and c="100" m="100" y="100" k="100" or
232
+ # c='100' m='100' y='100' k='100'
233
+ # color = { :rgb => "#ffffff" }
234
+ # color = { :r => 255, :g => 255, :b => 255 }
235
+ # color = { :c => 100, :m => 100, :y => 100, :k => 100 }
236
+ when /^<font[^>]*>$/
237
+ matches = /name="([^"]*)"/.match(token) ||
238
+ /name='([^']*)'/.match(token)
239
+ fonts << matches[1] unless matches.nil?
240
+
241
+ matches = /size="([^"]*)"/.match(token) ||
242
+ /size='([^']*)'/.match(token)
243
+ sizes << Float(matches[1]) unless matches.nil?
244
+
245
+ matches = /character_spacing="([^"]*)"/.match(token) ||
246
+ /character_spacing='([^']*)'/.match(token)
247
+ character_spacings << Float(matches[1]) unless matches.nil?
248
+ else
249
+ string = unescape(token)
250
+ array << {
251
+ text: string,
252
+ styles: styles.dup,
253
+ color: colors.last,
254
+ local: local,
255
+ link: link,
256
+ anchor: anchor,
257
+ font: fonts.last,
258
+ size: sizes.last,
259
+ character_spacing: character_spacings.last,
260
+ }
261
+ end
262
+ end
263
+ array
264
+ end
265
+
266
+ # Escape characters that can interfere with inline format parsing.
267
+ #
268
+ # @param text [String]
269
+ # @return [String]
270
+ def self.escape(text)
271
+ text.gsub(Regexp.union(ESCAPE_CHARS.keys), ESCAPE_CHARS)
272
+ end
273
+
274
+ # Unescape characters that can interfere with inline format parsing.
275
+ #
276
+ # @param text [String]
277
+ # @return [String]
278
+ def self.unescape(text)
279
+ text.gsub(Regexp.union(UNESCAPE_CHARS.keys), UNESCAPE_CHARS)
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'line_wrap'
4
+ require_relative 'arranger'
5
+
6
+ module Prawn
7
+ module Text
8
+ module Formatted
9
+ # Handles text wrapping for for formatted text.
10
+ #
11
+ # @private
12
+ module Wrap
13
+ def initialize(_array, options)
14
+ @line_wrap = Prawn::Text::Formatted::LineWrap.new
15
+ @arranger = Prawn::Text::Formatted::Arranger.new(
16
+ @document,
17
+ kerning: options[:kerning],
18
+ )
19
+ @disable_wrap_by_char = options[:disable_wrap_by_char]
20
+ end
21
+
22
+ # See the developer documentation for PDF::Core::Text#wrap
23
+ #
24
+ # Formatted#wrap should set the following variables:
25
+ # <tt>@line_height</tt>::
26
+ # the height of the tallest fragment in the last printed line
27
+ # <tt>@descender</tt>::
28
+ # the descender height of the tallest fragment in the last
29
+ # printed line
30
+ # <tt>@ascender</tt>::
31
+ # the ascender heigth of the tallest fragment in the last
32
+ # printed line
33
+ # <tt>@baseline_y</tt>::
34
+ # the baseline of the current line
35
+ # <tt>@nothing_printed</tt>::
36
+ # set to true until something is printed, then false
37
+ # <tt>@everything_printed</tt>::
38
+ # set to false until everything printed, then true
39
+ #
40
+ # Returns any formatted text that was not printed
41
+ #
42
+ def wrap(array)
43
+ initialize_wrap(array)
44
+
45
+ stop = false
46
+ until stop
47
+ # wrap before testing if enough height for this line because the
48
+ # height of the highest fragment on this line will be used to
49
+ # determine the line height
50
+ @line_wrap.wrap_line(
51
+ document: @document,
52
+ kerning: @kerning,
53
+ width: available_width,
54
+ arranger: @arranger,
55
+ disable_wrap_by_char: @disable_wrap_by_char,
56
+ )
57
+
58
+ if enough_height_for_this_line?
59
+ move_baseline_down
60
+ print_line
61
+ else
62
+ stop = true
63
+ end
64
+
65
+ stop ||= @single_line || @arranger.finished?
66
+ end
67
+ @text = @printed_lines.join("\n")
68
+ @everything_printed = @arranger.finished?
69
+ @arranger.unconsumed
70
+ end
71
+
72
+ private
73
+
74
+ def print_line
75
+ @nothing_printed = false
76
+ printed_fragments = []
77
+ fragments_this_line = []
78
+
79
+ word_spacing = word_spacing_for_this_line
80
+ @arranger.fragments.each do |fragment|
81
+ fragment.word_spacing = word_spacing
82
+ if fragment.text == "\n"
83
+ printed_fragments << "\n" if @printed_lines.last == ''
84
+ break
85
+ end
86
+ printed_fragments << fragment.text
87
+ fragments_this_line << fragment
88
+ end
89
+ @arranger.fragments.replace([])
90
+
91
+ accumulated_width = 0
92
+ fragments_this_line.reverse! if @direction == :rtl
93
+ fragments_this_line.each do |fragment_this_line|
94
+ fragment_this_line.default_direction = @direction
95
+ format_and_draw_fragment(
96
+ fragment_this_line,
97
+ accumulated_width,
98
+ @line_wrap.width,
99
+ word_spacing,
100
+ )
101
+ accumulated_width += fragment_this_line.width
102
+ end
103
+
104
+ @printed_lines << printed_fragments.map { |s|
105
+ s.dup.force_encoding(::Encoding::UTF_8)
106
+ }.join
107
+ end
108
+
109
+ def word_spacing_for_this_line
110
+ if @align == :justify && @line_wrap.space_count.positive? &&
111
+ !@line_wrap.paragraph_finished?
112
+ (available_width - @line_wrap.width) / @line_wrap.space_count
113
+ else
114
+ 0
115
+ end
116
+ end
117
+
118
+ def enough_height_for_this_line?
119
+ @line_height = @arranger.max_line_height
120
+ @descender = @arranger.max_descender
121
+ @ascender = @arranger.max_ascender
122
+ diff =
123
+ if @baseline_y.zero?
124
+ @ascender + @descender
125
+ else
126
+ @descender + @line_height + @leading
127
+ end
128
+ require_relatived_total_height = @baseline_y.abs + diff
129
+ if require_relatived_total_height > @height + 0.0001
130
+ # no room for the full height of this line
131
+ @arranger.repack_unretrieved
132
+ false
133
+ else
134
+ true
135
+ end
136
+ end
137
+
138
+ def initialize_wrap(array)
139
+ @text = nil
140
+ @arranger.format_array = array
141
+
142
+ # these values will depend on the maximum value within a given line
143
+ @line_height = 0
144
+ @descender = 0
145
+ @ascender = 0
146
+ @baseline_y = 0
147
+
148
+ @printed_lines = []
149
+ @nothing_printed = true
150
+ @everything_printed = false
151
+ end
152
+
153
+ def format_and_draw_fragment(fragment, accumulated_width, line_width, word_spacing)
154
+ @arranger.apply_color_and_font_settings(fragment) do
155
+ draw_fragment(
156
+ fragment,
157
+ accumulated_width,
158
+ line_width,
159
+ word_spacing,
160
+ )
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'formatted/wrap'
4
+
5
+ module Prawn
6
+ module Text
7
+ # Fancy pretty text.
8
+ module Formatted
9
+ # @group Stable API
10
+
11
+ # Draws the requested formatted text into a box.
12
+ #
13
+ # When the text overflows the rectangle shrink to fit or truncate the
14
+ # text. Text boxes are independent of the document y position.
15
+ #
16
+ # @example
17
+ # formatted_text_box([{ :text => "hello" },
18
+ # { :text => "world",
19
+ # :size => 24,
20
+ # :styles => [:bold, :italic] }])
21
+ #
22
+ # @param array [Array<Hash{Symbol => any}>]
23
+ # Formatted text is an array of hashes, where each hash defines text and
24
+ # format information. The following hash options are supported:
25
+ #
26
+ # - `:text` --- the text to format according to the other hash options.
27
+ # - `:styles` --- an array of styles to apply to this text. Available
28
+ # styles include `:bold`, `:italic`, `:underline`, `:strikethrough`,
29
+ # `:subscript`, and `:superscript`.
30
+ # - `:size` ---a number denoting the font size to apply to this text.
31
+ # - `:character_spacing` --- a number denoting how much to increase or
32
+ # decrease the default spacing between characters.
33
+ # - `:font` --- the name of a font. The name must be an AFM font with
34
+ # the desired faces or must be a font that is already registered using
35
+ # {Prawn::Document#font_families}.
36
+ # - `:color` --- anything compatible with
37
+ # {Prawn::Graphics::Color#fill_color} and
38
+ # {Prawn::Graphics::Color#stroke_color}.
39
+ # - :link` --- a URL to which to create a link. A clickable link will be
40
+ # created to that URL. Note that you must explicitly underline and
41
+ # color using the appropriate tags if you which to draw attention to
42
+ # the link.
43
+ # - `:anchor` --- a destination that has already been or will be
44
+ # registered using
45
+ # `PDF::Core::Destinations#add_dest`{:.language-plain}. A clickable
46
+ # link will be created to that destination. Note that you must
47
+ # explicitly underline and color using the appropriate tags if you
48
+ # which to draw attention to the link.
49
+ # - `:local` --- a file or application to be opened locally. A clickable
50
+ # link will be created to the provided local file or application. If
51
+ # the file is another PDF, it will be opened in a new window. Note
52
+ # that you must explicitly underline and color using the appropriate
53
+ # options if you which to draw attention to the link.
54
+ # - `:draw_text_callback` --- if provided, this Proc will be called
55
+ # instead of {#draw_text!} once per fragment for every low-level
56
+ # addition of text to the page.
57
+ # - `:callback` --- an object (or array of such objects) with two
58
+ # methods: `#render_behind`{:.language-plain} and
59
+ # `#render_in_front`{:.language-plain}, which are called immediately
60
+ # prior to and immediately after rendering the text fragment and which
61
+ # are passed the fragment as an argument.
62
+ # @param options [Hash{Symbol => any}]
63
+ # Accepts the same options as {Text::Box}.
64
+ #
65
+ # @return [Array<Hash>]
66
+ # A formatted text array representing any text that did not print under
67
+ # the current settings.
68
+ #
69
+ # @raise [Prawn::Text::Formatted::Arranger::BadFontFamily]
70
+ # If no font family is defined for the current font.
71
+ # @raise [Prawn::Errors::CannotFit]
72
+ # If not wide enough to print any text.
73
+ def formatted_text_box(array, options = {})
74
+ Text::Formatted::Box.new(array, options.merge(document: self)).render
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ require_relative 'formatted/box'
81
+ require_relative 'formatted/parser'
82
+ require_relative 'formatted/fragment'