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.
- checksums.yaml +7 -0
- data/giga-fast-kit.gemspec +12 -0
- data/prawn-2.5.0/COPYING +2 -0
- data/prawn-2.5.0/GPLv2 +339 -0
- data/prawn-2.5.0/GPLv3 +674 -0
- data/prawn-2.5.0/LICENSE +56 -0
- data/prawn-2.5.0/data/fonts/Courier-Bold.afm +342 -0
- data/prawn-2.5.0/data/fonts/Courier-BoldOblique.afm +342 -0
- data/prawn-2.5.0/data/fonts/Courier-Oblique.afm +342 -0
- data/prawn-2.5.0/data/fonts/Courier.afm +342 -0
- data/prawn-2.5.0/data/fonts/Helvetica-Bold.afm +2827 -0
- data/prawn-2.5.0/data/fonts/Helvetica-BoldOblique.afm +2827 -0
- data/prawn-2.5.0/data/fonts/Helvetica-Oblique.afm +3051 -0
- data/prawn-2.5.0/data/fonts/Helvetica.afm +3051 -0
- data/prawn-2.5.0/data/fonts/MustRead.html +19 -0
- data/prawn-2.5.0/data/fonts/Symbol.afm +213 -0
- data/prawn-2.5.0/data/fonts/Times-Bold.afm +2588 -0
- data/prawn-2.5.0/data/fonts/Times-BoldItalic.afm +2384 -0
- data/prawn-2.5.0/data/fonts/Times-Italic.afm +2667 -0
- data/prawn-2.5.0/data/fonts/Times-Roman.afm +2419 -0
- data/prawn-2.5.0/data/fonts/ZapfDingbats.afm +225 -0
- data/prawn-2.5.0/lib/prawn/document/bounding_box.rb +625 -0
- data/prawn-2.5.0/lib/prawn/document/column_box.rb +177 -0
- data/prawn-2.5.0/lib/prawn/document/internals.rb +76 -0
- data/prawn-2.5.0/lib/prawn/document/span.rb +65 -0
- data/prawn-2.5.0/lib/prawn/document.rb +846 -0
- data/prawn-2.5.0/lib/prawn/encoding.rb +85 -0
- data/prawn-2.5.0/lib/prawn/errors.rb +73 -0
- data/prawn-2.5.0/lib/prawn/font.rb +567 -0
- data/prawn-2.5.0/lib/prawn/font_metric_cache.rb +50 -0
- data/prawn-2.5.0/lib/prawn/fonts/afm.rb +332 -0
- data/prawn-2.5.0/lib/prawn/fonts/dfont.rb +42 -0
- data/prawn-2.5.0/lib/prawn/fonts/otf.rb +14 -0
- data/prawn-2.5.0/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
- data/prawn-2.5.0/lib/prawn/fonts/ttc.rb +41 -0
- data/prawn-2.5.0/lib/prawn/fonts/ttf.rb +615 -0
- data/prawn-2.5.0/lib/prawn/fonts.rb +14 -0
- data/prawn-2.5.0/lib/prawn/graphics/blend_mode.rb +62 -0
- data/prawn-2.5.0/lib/prawn/graphics/cap_style.rb +44 -0
- data/prawn-2.5.0/lib/prawn/graphics/color.rb +257 -0
- data/prawn-2.5.0/lib/prawn/graphics/dash.rb +123 -0
- data/prawn-2.5.0/lib/prawn/graphics/join_style.rb +60 -0
- data/prawn-2.5.0/lib/prawn/graphics/patterns.rb +389 -0
- data/prawn-2.5.0/lib/prawn/graphics/transformation.rb +172 -0
- data/prawn-2.5.0/lib/prawn/graphics/transparency.rb +79 -0
- data/prawn-2.5.0/lib/prawn/graphics.rb +791 -0
- data/prawn-2.5.0/lib/prawn/grid.rb +449 -0
- data/prawn-2.5.0/lib/prawn/image_handler.rb +61 -0
- data/prawn-2.5.0/lib/prawn/images/image.rb +48 -0
- data/prawn-2.5.0/lib/prawn/images/jpg.rb +121 -0
- data/prawn-2.5.0/lib/prawn/images/png.rb +383 -0
- data/prawn-2.5.0/lib/prawn/images.rb +195 -0
- data/prawn-2.5.0/lib/prawn/measurement_extensions.rb +82 -0
- data/prawn-2.5.0/lib/prawn/measurements.rb +129 -0
- data/prawn-2.5.0/lib/prawn/outline.rb +316 -0
- data/prawn-2.5.0/lib/prawn/repeater.rb +140 -0
- data/prawn-2.5.0/lib/prawn/security/arcfour.rb +54 -0
- data/prawn-2.5.0/lib/prawn/security.rb +308 -0
- data/prawn-2.5.0/lib/prawn/soft_mask.rb +105 -0
- data/prawn-2.5.0/lib/prawn/stamp.rb +147 -0
- data/prawn-2.5.0/lib/prawn/text/box.rb +192 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/arranger.rb +396 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/box.rb +725 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/fragment.rb +373 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/line_wrap.rb +335 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/parser.rb +284 -0
- data/prawn-2.5.0/lib/prawn/text/formatted/wrap.rb +166 -0
- data/prawn-2.5.0/lib/prawn/text/formatted.rb +82 -0
- data/prawn-2.5.0/lib/prawn/text.rb +701 -0
- data/prawn-2.5.0/lib/prawn/transformation_stack.rb +63 -0
- data/prawn-2.5.0/lib/prawn/utilities.rb +34 -0
- data/prawn-2.5.0/lib/prawn/version.rb +6 -0
- data/prawn-2.5.0/lib/prawn/view.rb +116 -0
- data/prawn-2.5.0/lib/prawn.rb +83 -0
- metadata +114 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'formatted/box'
|
|
4
|
+
|
|
5
|
+
module Prawn
|
|
6
|
+
module Text # rubocop: disable Style/Documentation
|
|
7
|
+
# @group Stable API
|
|
8
|
+
|
|
9
|
+
# Draws the requested text into a box.
|
|
10
|
+
#
|
|
11
|
+
# When the text overflows the rectangle, you shrink to fit, or truncate the
|
|
12
|
+
# text. Text boxes are independent of the document y position.
|
|
13
|
+
#
|
|
14
|
+
# #### Encoding
|
|
15
|
+
#
|
|
16
|
+
# Note that strings passed to this function should be encoded as UTF-8. If
|
|
17
|
+
# you get unexpected characters appearing in your rendered document, check
|
|
18
|
+
# this.
|
|
19
|
+
#
|
|
20
|
+
# If the current font is a built-in one, although the string must be encoded
|
|
21
|
+
# as UTF-8, only characters that are available in WinAnsi are allowed.
|
|
22
|
+
#
|
|
23
|
+
# If an empty box is rendered to your PDF instead of the character you
|
|
24
|
+
# wanted it usually means the current font doesn't include that character.
|
|
25
|
+
#
|
|
26
|
+
# @param string [String]
|
|
27
|
+
# @param options [Hash{Symbol => any}]
|
|
28
|
+
# @option options :kerning [Boolean] (value of document.default_kerning?)
|
|
29
|
+
# Whether or not to use kerning (if it is available with the current
|
|
30
|
+
# font).
|
|
31
|
+
# @option options :size [Number] (current font size)
|
|
32
|
+
# The font size to use.
|
|
33
|
+
# @option options :character_spacing [Number] (0)
|
|
34
|
+
# The amount of space to add to or remove from the default character
|
|
35
|
+
# spacing.
|
|
36
|
+
# @option options :disable_wrap_by_char [Boolean] (false)
|
|
37
|
+
# Whether or not to prevent mid-word breaks when text does not fit in box.
|
|
38
|
+
# @option options :mode [Symbol] (:fill)
|
|
39
|
+
# The text rendering mode. See documentation for
|
|
40
|
+
# {Prawn::Document#text_rendering_mode} for a list of valid options.
|
|
41
|
+
# @option option :style [Symbol] (current style)
|
|
42
|
+
# The style to use. The requested style must be part of the current font
|
|
43
|
+
# family.
|
|
44
|
+
# @option option :at [Array(Number, Number)] (bounds top left corner)
|
|
45
|
+
# The upper left corner of the box.
|
|
46
|
+
# @option options :width [Number] (bounds.right - at[0])
|
|
47
|
+
# The width of the box.
|
|
48
|
+
# @option options :height [Number] (default_height())
|
|
49
|
+
# The height of the box.
|
|
50
|
+
# @option options :direction [:ltr, :rtl] (value of document.text_direction)
|
|
51
|
+
# Direction of the text (left-to-right or right-to-left).
|
|
52
|
+
# @option options :fallback_fonts [Array<String>]
|
|
53
|
+
# An array of font names. Each name must be the name of an AFM font or the
|
|
54
|
+
# name that was used to register a family of external fonts (see
|
|
55
|
+
# {Prawn::Document#font_families}). If present, then each glyph will be
|
|
56
|
+
# rendered using the first font that includes the glyph, starting with the
|
|
57
|
+
# current font and then moving through `:fallback_fonts`.
|
|
58
|
+
# @option options :align [:left, :center, :right, :justify]
|
|
59
|
+
# (:left if direction is :ltr, :right if direction is :rtl)
|
|
60
|
+
# Alignment within the bounding box.
|
|
61
|
+
# @option options :valign [:top, :center, :bottom] (:top)
|
|
62
|
+
# Vertical alignment within the bounding box.
|
|
63
|
+
# @option options :rotate [Number]
|
|
64
|
+
# The angle to rotate the text.
|
|
65
|
+
# @option options :rotate_around
|
|
66
|
+
# [:center, :upper_left, :upper_right, :lower_right, :lower_left]
|
|
67
|
+
# (:upper_left)
|
|
68
|
+
# The point around which to rotate the text.
|
|
69
|
+
# @option options :leading [Number] (value of document.default_leading)
|
|
70
|
+
# Additional space between lines.
|
|
71
|
+
# @option options :single_line [Boolean] (false)
|
|
72
|
+
# If true, then only the first line will be drawn.
|
|
73
|
+
# @option options :overflow [:truncate, :shrink_to_fit, :expand] (:truncate)
|
|
74
|
+
# This controls the behavior when the amount of text exceeds the available
|
|
75
|
+
# space.
|
|
76
|
+
# @option options :min_font_size [Number] (5)
|
|
77
|
+
# The minimum font size to use when `:overflow` is set to `:shrink_to_fit`
|
|
78
|
+
# (that is the font size will not be reduced to less than this value, even
|
|
79
|
+
# if it means that some text will be cut off).
|
|
80
|
+
# @return [String] Any text that did not print under the current settings.
|
|
81
|
+
# @raise [Prawn::Errors::CannotFit]
|
|
82
|
+
# If not wide enough to print any text.
|
|
83
|
+
def text_box(string, options = {})
|
|
84
|
+
options = options.dup
|
|
85
|
+
options[:document] = self
|
|
86
|
+
|
|
87
|
+
box =
|
|
88
|
+
if options[:inline_format]
|
|
89
|
+
p = options.delete(:inline_format)
|
|
90
|
+
p = [] unless p.is_a?(Array)
|
|
91
|
+
array = text_formatter.format(string, *p)
|
|
92
|
+
Text::Formatted::Box.new(array, options)
|
|
93
|
+
else
|
|
94
|
+
Text::Box.new(string, options)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
box.render
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @group Experimental API
|
|
101
|
+
|
|
102
|
+
# Text box.
|
|
103
|
+
#
|
|
104
|
+
# Generally, one would use the {Prawn::Text#text_box} convenience method.
|
|
105
|
+
# However, using {Prawn::Text::Box#initialize Box.new} in conjunction with
|
|
106
|
+
# `render(dry_run: true)` enables one to do calculations prior to placing
|
|
107
|
+
# text on the page, or to determine how much vertical space was consumed by
|
|
108
|
+
# the printed text.
|
|
109
|
+
class Box < Prawn::Text::Formatted::Box
|
|
110
|
+
# @param string [String]
|
|
111
|
+
# @param options [Hash{Symbol => any}]
|
|
112
|
+
# @option options :document [Prawn::Document] Owning document.
|
|
113
|
+
# @option options :kerning [Boolean] (value of document.default_kerning?)
|
|
114
|
+
# Whether or not to use kerning (if it is available with the current
|
|
115
|
+
# font).
|
|
116
|
+
# @option options :size [Number] (current font size)
|
|
117
|
+
# The font size to use.
|
|
118
|
+
# @option options :character_spacing [Number] (0)
|
|
119
|
+
# The amount of space to add to or remove from the default character
|
|
120
|
+
# spacing.
|
|
121
|
+
# @option options :disable_wrap_by_char [Boolean] (false)
|
|
122
|
+
# Whether or not to prevent mid-word breaks when text does not fit in box.
|
|
123
|
+
# @option options :mode [Symbol] (:fill)
|
|
124
|
+
# The text rendering mode. See documentation for
|
|
125
|
+
# {Prawn::Document#text_rendering_mode} for a list of valid options.
|
|
126
|
+
# @option option :style [Symbol] (current style)
|
|
127
|
+
# The style to use. The requested style must be part of the current font
|
|
128
|
+
# family.
|
|
129
|
+
# @option option :at [Array(Number, Number)] (bounds top left corner)
|
|
130
|
+
# The upper left corner of the box.
|
|
131
|
+
# @option options :width [Number] (bounds.right - at[0])
|
|
132
|
+
# The width of the box.
|
|
133
|
+
# @option options :height [Number] (default_height())
|
|
134
|
+
# The height of the box.
|
|
135
|
+
# @option options :direction [:ltr, :rtl] (value of document.text_direction)
|
|
136
|
+
# Direction of the text (left-to-right or right-to-left).
|
|
137
|
+
# @option options :fallback_fonts [Array<String>]
|
|
138
|
+
# An array of font names. Each name must be the name of an AFM font or the
|
|
139
|
+
# name that was used to register a family of external fonts (see
|
|
140
|
+
# {Prawn::Document#font_families}). If present, then each glyph will be
|
|
141
|
+
# rendered using the first font that includes the glyph, starting with the
|
|
142
|
+
# current font and then moving through `:fallback_fonts`.
|
|
143
|
+
# @option options :align [:left, :center, :right, :justify]
|
|
144
|
+
# (:left if direction is :ltr, :right if direction is :rtl)
|
|
145
|
+
# Alignment within the bounding box.
|
|
146
|
+
# @option options :valign [:top, :center, :bottom] (:top)
|
|
147
|
+
# Vertical alignment within the bounding box.
|
|
148
|
+
# @option options :rotate [Number]
|
|
149
|
+
# The angle to rotate the text.
|
|
150
|
+
# @option options :rotate_around
|
|
151
|
+
# [:center, :upper_left, :upper_right, :lower_right, :lower_left]
|
|
152
|
+
# (:upper_left)
|
|
153
|
+
# The point around which to rotate the text.
|
|
154
|
+
# @option options :leading [Number] (value of document.default_leading)
|
|
155
|
+
# Additional space between lines.
|
|
156
|
+
# @option options :single_line [Boolean] (false)
|
|
157
|
+
# If true, then only the first line will be drawn.
|
|
158
|
+
# @option options :overflow [:truncate, :shrink_to_fit, :expand] (:truncate)
|
|
159
|
+
# This controls the behavior when the amount of text exceeds the available
|
|
160
|
+
# space.
|
|
161
|
+
# @option options :min_font_size [Number] (5)
|
|
162
|
+
# The minimum font size to use when `:overflow` is set to `:shrink_to_fit`
|
|
163
|
+
# (that is the font size will not be reduced to less than this value, even
|
|
164
|
+
# if it means that some text will be cut off).
|
|
165
|
+
def initialize(string, options = {})
|
|
166
|
+
super([{ text: string }], options)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Render text to the document based on the settings defined in
|
|
170
|
+
# constructor.
|
|
171
|
+
#
|
|
172
|
+
# In order to facilitate look-ahead calculations, this method accepts
|
|
173
|
+
# a `dry_run: true` option. If provided, then everything is executed as if
|
|
174
|
+
# rendering, with the exception that nothing is drawn on the page. Useful
|
|
175
|
+
# for look-ahead computations of height, unprinted text, etc.
|
|
176
|
+
#
|
|
177
|
+
# @param flags [Hash{Symbol => any}]
|
|
178
|
+
# @option flags :dry_run [Boolean] (false)
|
|
179
|
+
# Do not draw the text. Everything else is done.
|
|
180
|
+
# @return [String]
|
|
181
|
+
# Any text that did not print under the current settings.
|
|
182
|
+
# @raise [Prawn::Text::Formatted::Arranger::BadFontFamily]
|
|
183
|
+
# If no font family is defined for the current font.
|
|
184
|
+
# @raise [Prawn::Errors::CannotFit]
|
|
185
|
+
# If not wide enough to print any text.
|
|
186
|
+
def render(flags = {})
|
|
187
|
+
leftover = super(flags)
|
|
188
|
+
leftover.map { |hash| hash[:text] }.join
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prawn
|
|
4
|
+
module Text
|
|
5
|
+
module Formatted
|
|
6
|
+
# D data structure for 2-stage processing of lines of formatted text.
|
|
7
|
+
# @private
|
|
8
|
+
class Arranger
|
|
9
|
+
# You're getting this because you're trying to get some information from
|
|
10
|
+
# the arranger before it finished processing text.
|
|
11
|
+
class NotFinalized < StandardError
|
|
12
|
+
# @private
|
|
13
|
+
DEFAULT_MESSAGE = 'Lines must be finalized'
|
|
14
|
+
|
|
15
|
+
# @private
|
|
16
|
+
MESSAGE_WITH_METHOD = 'Lines must be finalized before calling #%<method>s'
|
|
17
|
+
|
|
18
|
+
def initialize(message = DEFAULT_MESSAGE, method: nil)
|
|
19
|
+
if method && message == DEFAULT_MESSAGE
|
|
20
|
+
super(format(MESSAGE_WITH_METHOD, method: method))
|
|
21
|
+
else
|
|
22
|
+
super(message)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# You're getting this because a font doesn't have a family name.
|
|
28
|
+
class BadFontFamily < StandardError
|
|
29
|
+
def initialize(message = 'Bad font family')
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attr_reader :max_line_height
|
|
35
|
+
attr_reader :max_descender
|
|
36
|
+
attr_reader :max_ascender
|
|
37
|
+
attr_reader :finalized
|
|
38
|
+
attr_accessor :consumed
|
|
39
|
+
|
|
40
|
+
# The following present only for testing purposes
|
|
41
|
+
attr_reader :unconsumed
|
|
42
|
+
attr_reader :fragments
|
|
43
|
+
attr_reader :current_format_state
|
|
44
|
+
|
|
45
|
+
def initialize(document, options = {})
|
|
46
|
+
@document = document
|
|
47
|
+
@fragments = []
|
|
48
|
+
@unconsumed = []
|
|
49
|
+
@kerning = options[:kerning]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Number of spaces in the text.
|
|
53
|
+
#
|
|
54
|
+
# @return [Integer]
|
|
55
|
+
# @raise [NotFinalized]
|
|
56
|
+
def space_count
|
|
57
|
+
unless finalized
|
|
58
|
+
raise NotFinalized.new(method: 'space_count')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@fragments.reduce(0) do |sum, fragment|
|
|
62
|
+
sum + fragment.space_count
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Line width.
|
|
67
|
+
#
|
|
68
|
+
# @return [Number]
|
|
69
|
+
# @raise [NotFinalized]
|
|
70
|
+
def line_width
|
|
71
|
+
unless finalized
|
|
72
|
+
raise raise NotFinalized.new(method: 'line_width')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
@fragments.reduce(0) do |sum, fragment|
|
|
76
|
+
sum + fragment.width
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Line text.
|
|
81
|
+
#
|
|
82
|
+
# @return [String]
|
|
83
|
+
# @raise [NotFinalized]
|
|
84
|
+
def line
|
|
85
|
+
unless finalized
|
|
86
|
+
raise NotFinalized.new(method: 'line')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
@fragments.map { |fragment|
|
|
90
|
+
begin
|
|
91
|
+
fragment.text.dup.encode(::Encoding::UTF_8)
|
|
92
|
+
rescue ::Encoding::InvalidByteSequenceError, ::Encoding::UndefinedConversionError
|
|
93
|
+
fragment.text.dup.force_encoding(::Encoding::UTF_8)
|
|
94
|
+
end
|
|
95
|
+
}.join
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Finish laying out current line.
|
|
99
|
+
#
|
|
100
|
+
# @return [void]
|
|
101
|
+
def finalize_line
|
|
102
|
+
@finalized = true
|
|
103
|
+
|
|
104
|
+
omit_trailing_whitespace_from_line_width
|
|
105
|
+
@fragments = []
|
|
106
|
+
@consumed.each do |hash|
|
|
107
|
+
text = hash[:text]
|
|
108
|
+
format_state = hash.dup
|
|
109
|
+
format_state.delete(:text)
|
|
110
|
+
fragment = Prawn::Text::Formatted::Fragment.new(
|
|
111
|
+
text,
|
|
112
|
+
format_state,
|
|
113
|
+
@document,
|
|
114
|
+
)
|
|
115
|
+
@fragments << fragment
|
|
116
|
+
self.fragment_measurements = fragment
|
|
117
|
+
self.line_measurement_maximums = fragment
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Set new fragment array.
|
|
122
|
+
#
|
|
123
|
+
# @param array [Array<Hash>]
|
|
124
|
+
# @return [void]
|
|
125
|
+
def format_array=(array)
|
|
126
|
+
initialize_line
|
|
127
|
+
@unconsumed = []
|
|
128
|
+
array.each do |hash|
|
|
129
|
+
hash[:text].scan(/[^\n]+|\n/) do |line|
|
|
130
|
+
@unconsumed << hash.merge(text: line)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Prepare for new line layout.
|
|
136
|
+
#
|
|
137
|
+
# @return [void]
|
|
138
|
+
def initialize_line
|
|
139
|
+
@finalized = false
|
|
140
|
+
@max_line_height = 0
|
|
141
|
+
@max_descender = 0
|
|
142
|
+
@max_ascender = 0
|
|
143
|
+
|
|
144
|
+
@consumed = []
|
|
145
|
+
@fragments = []
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Were all fragments processed?
|
|
149
|
+
#
|
|
150
|
+
# @return [Boolean]
|
|
151
|
+
def finished?
|
|
152
|
+
@unconsumed.empty?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Get the next unprocessed string.
|
|
156
|
+
#
|
|
157
|
+
# @return [String, nil]
|
|
158
|
+
# @raise [NotFinalized]
|
|
159
|
+
def next_string
|
|
160
|
+
if finalized
|
|
161
|
+
raise NotFinalized.new(method: 'next_string')
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
next_unconsumed_hash = @unconsumed.shift
|
|
165
|
+
|
|
166
|
+
if next_unconsumed_hash
|
|
167
|
+
@consumed << next_unconsumed_hash.dup
|
|
168
|
+
@current_format_state = next_unconsumed_hash.dup
|
|
169
|
+
@current_format_state.delete(:text)
|
|
170
|
+
|
|
171
|
+
next_unconsumed_hash[:text]
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Get the next unprocessed string keeping it in the queue.
|
|
176
|
+
#
|
|
177
|
+
# @return [String, nil]
|
|
178
|
+
def preview_next_string
|
|
179
|
+
next_unconsumed_hash = @unconsumed.first
|
|
180
|
+
|
|
181
|
+
if next_unconsumed_hash
|
|
182
|
+
next_unconsumed_hash[:text]
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Apply color and font settings.
|
|
187
|
+
#
|
|
188
|
+
# @param fragment [Prawn::Text::Formatted::Fragment]
|
|
189
|
+
# @yield
|
|
190
|
+
# @return [void]
|
|
191
|
+
def apply_color_and_font_settings(fragment, &block)
|
|
192
|
+
if fragment.color
|
|
193
|
+
original_fill_color = @document.fill_color
|
|
194
|
+
original_stroke_color = @document.stroke_color
|
|
195
|
+
@document.fill_color(*fragment.color)
|
|
196
|
+
@document.stroke_color(*fragment.color)
|
|
197
|
+
apply_font_settings(fragment, &block)
|
|
198
|
+
@document.stroke_color = original_stroke_color
|
|
199
|
+
@document.fill_color = original_fill_color
|
|
200
|
+
else
|
|
201
|
+
apply_font_settings(fragment, &block)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Apply font settings.
|
|
206
|
+
#
|
|
207
|
+
# @param fragment [Prawn::Text::Formatted::Fragment]
|
|
208
|
+
# @yield
|
|
209
|
+
# @return [void]
|
|
210
|
+
def apply_font_settings(fragment = nil, &block)
|
|
211
|
+
if fragment.nil?
|
|
212
|
+
font = current_format_state[:font]
|
|
213
|
+
size = current_format_state[:size]
|
|
214
|
+
character_spacing = current_format_state[:character_spacing] ||
|
|
215
|
+
@document.character_spacing
|
|
216
|
+
styles = current_format_state[:styles]
|
|
217
|
+
else
|
|
218
|
+
font = fragment.font
|
|
219
|
+
size = fragment.size
|
|
220
|
+
character_spacing = fragment.character_spacing
|
|
221
|
+
styles = fragment.styles
|
|
222
|
+
end
|
|
223
|
+
font_style = font_style(styles)
|
|
224
|
+
|
|
225
|
+
@document.character_spacing(character_spacing) do
|
|
226
|
+
if font || font_style != :normal
|
|
227
|
+
raise BadFontFamily unless @document.font.family
|
|
228
|
+
|
|
229
|
+
@document.font(
|
|
230
|
+
font || @document.font.family, style: font_style,
|
|
231
|
+
) do
|
|
232
|
+
apply_font_size(size, styles, &block)
|
|
233
|
+
end
|
|
234
|
+
else
|
|
235
|
+
apply_font_size(size, styles, &block)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Update last fragment's text.
|
|
241
|
+
#
|
|
242
|
+
# @param printed [String]
|
|
243
|
+
# @param unprinted [String]
|
|
244
|
+
# @param normalized_soft_hyphen [Boolean]
|
|
245
|
+
# @return [void]
|
|
246
|
+
def update_last_string(printed, unprinted, normalized_soft_hyphen = nil)
|
|
247
|
+
return if printed.nil?
|
|
248
|
+
|
|
249
|
+
if printed.empty?
|
|
250
|
+
@consumed.pop
|
|
251
|
+
else
|
|
252
|
+
@consumed.last[:text] = printed
|
|
253
|
+
if normalized_soft_hyphen
|
|
254
|
+
@consumed.last[:normalized_soft_hyphen] = normalized_soft_hyphen
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
unless unprinted.empty?
|
|
259
|
+
@unconsumed.unshift(@current_format_state.merge(text: unprinted))
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
load_previous_format_state if printed.empty?
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Get the next fragment.
|
|
266
|
+
#
|
|
267
|
+
# @return [Prawn::Text::Formatted::Fragment]
|
|
268
|
+
# @raise [NotFinalized]
|
|
269
|
+
def retrieve_fragment
|
|
270
|
+
unless finalized
|
|
271
|
+
raise NotFinalized, 'Lines must be finalized before fragments can be retrieved'
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
@fragments.shift
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Repack remaining fragments.
|
|
278
|
+
#
|
|
279
|
+
# @return [void]
|
|
280
|
+
def repack_unretrieved
|
|
281
|
+
new_unconsumed = []
|
|
282
|
+
# rubocop: disable Lint/AssignmentInCondition
|
|
283
|
+
while fragment = retrieve_fragment
|
|
284
|
+
# rubocop: enable Lint/AssignmentInCondition
|
|
285
|
+
fragment.include_trailing_white_space!
|
|
286
|
+
new_unconsumed << fragment.format_state.merge(text: fragment.text)
|
|
287
|
+
end
|
|
288
|
+
@unconsumed = new_unconsumed.concat(@unconsumed)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Get font variant from fragment styles.
|
|
292
|
+
#
|
|
293
|
+
# @param styles [Array<Symbol>]
|
|
294
|
+
# @return [Symbol]
|
|
295
|
+
def font_style(styles)
|
|
296
|
+
styles = Array(styles)
|
|
297
|
+
if styles.include?(:bold) && styles.include?(:italic)
|
|
298
|
+
:bold_italic
|
|
299
|
+
elsif styles.include?(:bold)
|
|
300
|
+
:bold
|
|
301
|
+
elsif styles.include?(:italic)
|
|
302
|
+
:italic
|
|
303
|
+
else
|
|
304
|
+
:normal
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
private
|
|
309
|
+
|
|
310
|
+
def load_previous_format_state
|
|
311
|
+
if @consumed.empty?
|
|
312
|
+
@current_format_state = {}
|
|
313
|
+
else
|
|
314
|
+
hash = @consumed.last
|
|
315
|
+
@current_format_state = hash.dup
|
|
316
|
+
@current_format_state.delete(:text)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def apply_font_size(size, styles, &block)
|
|
321
|
+
if subscript?(styles) || superscript?(styles)
|
|
322
|
+
relative_size = 0.583
|
|
323
|
+
size =
|
|
324
|
+
if size.nil?
|
|
325
|
+
@document.font_size * relative_size
|
|
326
|
+
else
|
|
327
|
+
size * relative_size
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
if size.nil?
|
|
331
|
+
yield
|
|
332
|
+
else
|
|
333
|
+
@document.font_size(size, &block)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def subscript?(styles)
|
|
338
|
+
if styles.nil? then false
|
|
339
|
+
else
|
|
340
|
+
styles.include?(:subscript)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def superscript?(styles)
|
|
345
|
+
if styles.nil? then false
|
|
346
|
+
else
|
|
347
|
+
styles.include?(:superscript)
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def omit_trailing_whitespace_from_line_width
|
|
352
|
+
@consumed.reverse_each do |hash|
|
|
353
|
+
if hash[:text] == "\n"
|
|
354
|
+
break
|
|
355
|
+
elsif hash[:text].strip.empty? && @consumed.length > 1
|
|
356
|
+
# this entire fragment is trailing white space
|
|
357
|
+
hash[:exclude_trailing_white_space] = true
|
|
358
|
+
else
|
|
359
|
+
# this fragment contains the first non-white space we have
|
|
360
|
+
# encountered since the end of the line
|
|
361
|
+
hash[:exclude_trailing_white_space] = true
|
|
362
|
+
break
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def fragment_measurements=(fragment)
|
|
368
|
+
apply_font_settings(fragment) do
|
|
369
|
+
fragment.width = @document.width_of(
|
|
370
|
+
fragment.text,
|
|
371
|
+
kerning: @kerning,
|
|
372
|
+
)
|
|
373
|
+
fragment.line_height = @document.font.height
|
|
374
|
+
fragment.descender = @document.font.descender
|
|
375
|
+
fragment.ascender = @document.font.ascender
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def line_measurement_maximums=(fragment)
|
|
380
|
+
@max_line_height = [
|
|
381
|
+
defined?(@max_line_height) && @max_line_height,
|
|
382
|
+
fragment.line_height,
|
|
383
|
+
].compact.max
|
|
384
|
+
@max_descender = [
|
|
385
|
+
defined?(@max_descender) && @max_descender,
|
|
386
|
+
fragment.descender,
|
|
387
|
+
].compact.max
|
|
388
|
+
@max_ascender = [
|
|
389
|
+
defined?(@max_ascender) && @max_ascender,
|
|
390
|
+
fragment.ascender,
|
|
391
|
+
].compact.max
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
end
|