prawn 2.1.0 → 2.4.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +9 -41
- data/lib/prawn.rb +37 -49
- data/lib/prawn/document.rb +193 -141
- data/lib/prawn/document/bounding_box.rb +50 -30
- data/lib/prawn/document/column_box.rb +7 -7
- data/lib/prawn/document/internals.rb +8 -6
- data/lib/prawn/document/span.rb +22 -16
- data/lib/prawn/encoding.rb +69 -68
- data/lib/prawn/errors.rb +12 -7
- data/lib/prawn/font.rb +104 -69
- data/lib/prawn/font_metric_cache.rb +20 -13
- data/lib/prawn/{font → fonts}/afm.rb +108 -72
- data/lib/prawn/{font → fonts}/dfont.rb +5 -11
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +126 -81
- data/lib/prawn/graphics.rb +119 -81
- data/lib/prawn/graphics/blend_mode.rb +9 -8
- data/lib/prawn/graphics/cap_style.rb +3 -3
- data/lib/prawn/graphics/color.rb +43 -39
- data/lib/prawn/graphics/dash.rb +23 -11
- data/lib/prawn/graphics/join_style.rb +9 -3
- data/lib/prawn/graphics/patterns.rb +204 -102
- data/lib/prawn/graphics/transformation.rb +15 -9
- data/lib/prawn/graphics/transparency.rb +17 -13
- data/lib/prawn/grid.rb +84 -48
- data/lib/prawn/image_handler.rb +5 -5
- data/lib/prawn/images.rb +60 -49
- data/lib/prawn/images/image.rb +2 -1
- data/lib/prawn/images/jpg.rb +31 -22
- data/lib/prawn/images/png.rb +67 -63
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +19 -15
- data/lib/prawn/outline.rb +98 -77
- data/lib/prawn/repeater.rb +15 -11
- data/lib/prawn/security.rb +93 -70
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/soft_mask.rb +26 -26
- data/lib/prawn/stamp.rb +20 -13
- data/lib/prawn/text.rb +76 -60
- data/lib/prawn/text/box.rb +18 -14
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text/formatted/arranger.rb +80 -40
- data/lib/prawn/text/formatted/box.rb +140 -101
- data/lib/prawn/text/formatted/fragment.rb +11 -14
- data/lib/prawn/text/formatted/line_wrap.rb +128 -67
- data/lib/prawn/text/formatted/parser.rb +147 -123
- data/lib/prawn/text/formatted/wrap.rb +48 -32
- data/lib/prawn/transformation_stack.rb +7 -5
- data/lib/prawn/utilities.rb +7 -22
- data/lib/prawn/version.rb +2 -2
- data/lib/prawn/view.rb +17 -7
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +31 -22
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +7 -8
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +22 -16
- data/manual/bounding_box/bounding_box.rb +29 -24
- data/manual/bounding_box/bounds.rb +11 -12
- data/manual/bounding_box/canvas.rb +7 -8
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +25 -18
- data/manual/bounding_box/russian_boxes.rb +14 -13
- data/manual/bounding_box/stretchy.rb +12 -13
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -28
- data/manual/document_and_page_options/background.rb +15 -13
- data/manual/document_and_page_options/document_and_page_options.rb +25 -20
- data/manual/document_and_page_options/metadata.rb +18 -16
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -12
- data/manual/document_and_page_options/print_scaling.rb +18 -15
- data/manual/example_helper.rb +5 -4
- data/manual/graphics/blend_mode.rb +12 -9
- data/manual/graphics/circle_and_ellipse.rb +4 -5
- data/manual/graphics/color.rb +7 -9
- data/manual/graphics/common_lines.rb +7 -8
- data/manual/graphics/fill_and_stroke.rb +5 -6
- data/manual/graphics/fill_rules.rb +10 -10
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +48 -40
- data/manual/graphics/helper.rb +19 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +7 -8
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -7
- data/manual/graphics/scale.rb +14 -15
- data/manual/graphics/soft_masks.rb +3 -4
- data/manual/graphics/stroke_cap.rb +6 -7
- data/manual/graphics/stroke_dash.rb +15 -16
- data/manual/graphics/stroke_join.rb +5 -6
- data/manual/graphics/translate.rb +10 -10
- data/manual/graphics/transparency.rb +7 -8
- data/manual/how_to_read_this_manual.rb +6 -6
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +10 -11
- data/manual/images/images.rb +28 -24
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +16 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +5 -6
- data/manual/layout/content.rb +7 -8
- data/manual/layout/layout.rb +18 -16
- data/manual/layout/simple_grid.rb +6 -7
- data/manual/outline/add_subsection_to.rb +20 -21
- data/manual/outline/insert_section_after.rb +15 -16
- data/manual/outline/outline.rb +21 -17
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +25 -19
- data/manual/repeatable_content/repeater.rb +14 -15
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +9 -10
- data/manual/security/permissions.rb +21 -14
- data/manual/security/security.rb +19 -16
- data/manual/table.rb +3 -3
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -11
- data/manual/text/column_box.rb +9 -10
- data/manual/text/fallback_fonts.rb +25 -21
- data/manual/text/font.rb +11 -12
- data/manual/text/font_size.rb +13 -14
- data/manual/text/font_style.rb +10 -8
- data/manual/text/formatted_callbacks.rb +33 -24
- data/manual/text/formatted_text.rb +36 -25
- data/manual/text/free_flowing_text.rb +22 -23
- data/manual/text/inline.rb +18 -19
- data/manual/text/kerning_and_character_spacing.rb +14 -15
- data/manual/text/leading.rb +7 -8
- data/manual/text/line_wrapping.rb +37 -18
- data/manual/text/paragraph_indentation.rb +12 -14
- data/manual/text/positioned_text.rb +15 -16
- data/manual/text/registering_families.rb +20 -21
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +26 -19
- data/manual/text/rotation.rb +33 -23
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +57 -52
- data/manual/text/text_box_excess.rb +20 -17
- data/manual/text/text_box_extensions.rb +18 -15
- data/manual/text/text_box_overflow.rb +20 -19
- data/manual/text/utf8.rb +11 -12
- data/manual/text/win_ansi_charset.rb +27 -25
- data/prawn.gemspec +41 -34
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +550 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +44 -0
- data/spec/prawn/document_spec.rb +805 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +544 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +872 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +14 -14
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +229 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +512 -0
- data/spec/prawn/repeater_spec.rb +166 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +173 -0
- data/spec/prawn/text/box_spec.rb +1110 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +849 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +150 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +22 -19
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +18 -19
- metadata +102 -222
- metadata.gz.sig +0 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/blend_modes_bottom_layer.jpg +0 -0
- data/data/images/blend_modes_top_layer.jpg +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/fractal.jpg +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/indexed_transparency.png +0 -0
- data/data/images/indexed_transparency_alpha.dat +0 -0
- data/data/images/indexed_transparency_color.dat +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/license.md +0 -8
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/spec/acceptance/png_spec.rb +0 -35
- data/spec/annotations_spec.rb +0 -67
- data/spec/blend_mode_spec.rb +0 -71
- data/spec/bounding_box_spec.rb +0 -501
- data/spec/column_box_spec.rb +0 -59
- data/spec/destinations_spec.rb +0 -13
- data/spec/document_spec.rb +0 -738
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -452
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -705
- data/spec/grid_spec.rb +0 -95
- data/spec/images_spec.rb +0 -167
- data/spec/inline_formatted_text_parser_spec.rb +0 -568
- data/spec/jpg_spec.rb +0 -23
- data/spec/line_wrap_spec.rb +0 -366
- data/spec/measurement_units_spec.rb +0 -22
- data/spec/outline_spec.rb +0 -409
- data/spec/png_spec.rb +0 -257
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -154
- data/spec/security_spec.rb +0 -151
- data/spec/soft_mask_spec.rb +0 -78
- data/spec/span_spec.rb +0 -43
- data/spec/stamp_spec.rb +0 -179
- data/spec/stroke_styles_spec.rb +0 -208
- data/spec/text_at_spec.rb +0 -142
- data/spec/text_box_spec.rb +0 -1042
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -543
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
- data/spec/view_spec.rb +0 -42
data/lib/prawn/text/formatted.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'formatted/wrap'
|
4
4
|
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
5
|
+
require_relative 'formatted/box'
|
6
|
+
require_relative 'formatted/parser'
|
7
|
+
require_relative 'formatted/fragment'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# core/text/formatted/arranger.rb : Implements a data structure for 2-stage
|
4
4
|
# processing of lines of formatted text
|
@@ -13,6 +13,25 @@ module Prawn
|
|
13
13
|
# @private
|
14
14
|
|
15
15
|
class Arranger #:nodoc:
|
16
|
+
class NotFinalized < StandardError
|
17
|
+
DEFAULT_MESSAGE = 'Lines must be finalized'
|
18
|
+
MESSAGE_WITH_METHOD = 'Lines must be finalized before calling #%<method>s'
|
19
|
+
|
20
|
+
def initialize(message = DEFAULT_MESSAGE, method: nil)
|
21
|
+
if method && message == DEFAULT_MESSAGE
|
22
|
+
super format(MESSAGE_WITH_METHOD, method: method)
|
23
|
+
else
|
24
|
+
super message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class BadFontFamily < StandardError
|
30
|
+
def initialize(message = 'Bad font family')
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
16
35
|
attr_reader :max_line_height
|
17
36
|
attr_reader :max_descender
|
18
37
|
attr_reader :max_ascender
|
@@ -33,30 +52,33 @@ module Prawn
|
|
33
52
|
|
34
53
|
def space_count
|
35
54
|
unless finalized
|
36
|
-
|
55
|
+
raise NotFinalized.new(method: 'space_count')
|
37
56
|
end
|
38
57
|
|
39
|
-
@fragments.
|
58
|
+
@fragments.reduce(0) do |sum, fragment|
|
40
59
|
sum + fragment.space_count
|
41
60
|
end
|
42
61
|
end
|
43
62
|
|
44
63
|
def line_width
|
45
64
|
unless finalized
|
46
|
-
|
65
|
+
raise raise NotFinalized.new(method: 'line_width')
|
47
66
|
end
|
48
67
|
|
49
|
-
@fragments.
|
68
|
+
@fragments.reduce(0) do |sum, fragment|
|
50
69
|
sum + fragment.width
|
51
70
|
end
|
52
71
|
end
|
53
72
|
|
54
73
|
def line
|
55
74
|
unless finalized
|
56
|
-
|
75
|
+
raise NotFinalized.new(method: 'line')
|
57
76
|
end
|
58
77
|
|
59
|
-
@fragments.
|
78
|
+
@fragments.map do |fragment|
|
79
|
+
fragment.text.dup.encode(::Encoding::UTF_8)
|
80
|
+
rescue ::Encoding::InvalidByteSequenceError,
|
81
|
+
::Encoding::UndefinedConversionError
|
60
82
|
fragment.text.dup.force_encoding(::Encoding::UTF_8)
|
61
83
|
end.join
|
62
84
|
end
|
@@ -70,12 +92,14 @@ module Prawn
|
|
70
92
|
text = hash[:text]
|
71
93
|
format_state = hash.dup
|
72
94
|
format_state.delete(:text)
|
73
|
-
fragment = Prawn::Text::Formatted::Fragment.new(
|
74
|
-
|
75
|
-
|
95
|
+
fragment = Prawn::Text::Formatted::Fragment.new(
|
96
|
+
text,
|
97
|
+
format_state,
|
98
|
+
@document
|
99
|
+
)
|
76
100
|
@fragments << fragment
|
77
|
-
|
78
|
-
|
101
|
+
self.fragment_measurements = fragment
|
102
|
+
self.line_measurement_maximums = fragment
|
79
103
|
end
|
80
104
|
end
|
81
105
|
|
@@ -84,7 +108,7 @@ module Prawn
|
|
84
108
|
@unconsumed = []
|
85
109
|
array.each do |hash|
|
86
110
|
hash[:text].scan(/[^\n]+|\n/) do |line|
|
87
|
-
@unconsumed << hash.merge(:
|
111
|
+
@unconsumed << hash.merge(text: line)
|
88
112
|
end
|
89
113
|
end
|
90
114
|
end
|
@@ -100,12 +124,12 @@ module Prawn
|
|
100
124
|
end
|
101
125
|
|
102
126
|
def finished?
|
103
|
-
@unconsumed.
|
127
|
+
@unconsumed.empty?
|
104
128
|
end
|
105
129
|
|
106
130
|
def next_string
|
107
131
|
if finalized
|
108
|
-
|
132
|
+
raise NotFinalized.new(method: 'next_string')
|
109
133
|
end
|
110
134
|
|
111
135
|
next_unconsumed_hash = @unconsumed.shift
|
@@ -146,21 +170,23 @@ module Prawn
|
|
146
170
|
font = current_format_state[:font]
|
147
171
|
size = current_format_state[:size]
|
148
172
|
character_spacing = current_format_state[:character_spacing] ||
|
149
|
-
|
173
|
+
@document.character_spacing
|
150
174
|
styles = current_format_state[:styles]
|
151
|
-
font_style = font_style(styles)
|
152
175
|
else
|
153
176
|
font = fragment.font
|
154
177
|
size = fragment.size
|
155
178
|
character_spacing = fragment.character_spacing
|
156
179
|
styles = fragment.styles
|
157
|
-
font_style = font_style(styles)
|
158
180
|
end
|
181
|
+
font_style = font_style(styles)
|
159
182
|
|
160
183
|
@document.character_spacing(character_spacing) do
|
161
184
|
if font || font_style != :normal
|
162
|
-
|
163
|
-
|
185
|
+
raise BadFontFamily unless @document.font.family
|
186
|
+
|
187
|
+
@document.font(
|
188
|
+
font || @document.font.family, style: font_style
|
189
|
+
) do
|
164
190
|
apply_font_size(size, styles, &block)
|
165
191
|
end
|
166
192
|
else
|
@@ -171,6 +197,7 @@ module Prawn
|
|
171
197
|
|
172
198
|
def update_last_string(printed, unprinted, normalized_soft_hyphen = nil)
|
173
199
|
return if printed.nil?
|
200
|
+
|
174
201
|
if printed.empty?
|
175
202
|
@consumed.pop
|
176
203
|
else
|
@@ -181,7 +208,7 @@ module Prawn
|
|
181
208
|
end
|
182
209
|
|
183
210
|
unless unprinted.empty?
|
184
|
-
@unconsumed.unshift(@current_format_state.merge(:
|
211
|
+
@unconsumed.unshift(@current_format_state.merge(text: unprinted))
|
185
212
|
end
|
186
213
|
|
187
214
|
load_previous_format_state if printed.empty?
|
@@ -189,7 +216,7 @@ module Prawn
|
|
189
216
|
|
190
217
|
def retrieve_fragment
|
191
218
|
unless finalized
|
192
|
-
|
219
|
+
raise NotFinalized, 'Lines must be finalized before fragments can be retrieved'
|
193
220
|
end
|
194
221
|
|
195
222
|
@fragments.shift
|
@@ -197,17 +224,18 @@ module Prawn
|
|
197
224
|
|
198
225
|
def repack_unretrieved
|
199
226
|
new_unconsumed = []
|
227
|
+
# rubocop: disable Lint/AssignmentInCondition
|
200
228
|
while fragment = retrieve_fragment
|
229
|
+
# rubocop: enable Lint/AssignmentInCondition
|
201
230
|
fragment.include_trailing_white_space!
|
202
|
-
new_unconsumed << fragment.format_state.merge(:
|
231
|
+
new_unconsumed << fragment.format_state.merge(text: fragment.text)
|
203
232
|
end
|
204
233
|
@unconsumed = new_unconsumed.concat(@unconsumed)
|
205
234
|
end
|
206
235
|
|
207
236
|
def font_style(styles)
|
208
|
-
|
209
|
-
|
210
|
-
elsif styles.include?(:bold) && styles.include?(:italic)
|
237
|
+
styles = Array(styles)
|
238
|
+
if styles.include?(:bold) && styles.include?(:italic)
|
211
239
|
:bold_italic
|
212
240
|
elsif styles.include?(:bold)
|
213
241
|
:bold
|
@@ -230,19 +258,20 @@ module Prawn
|
|
230
258
|
end
|
231
259
|
end
|
232
260
|
|
233
|
-
def apply_font_size(size, styles)
|
261
|
+
def apply_font_size(size, styles, &block)
|
234
262
|
if subscript?(styles) || superscript?(styles)
|
235
263
|
relative_size = 0.583
|
236
|
-
|
237
|
-
size
|
238
|
-
|
239
|
-
|
240
|
-
|
264
|
+
size =
|
265
|
+
if size.nil?
|
266
|
+
@document.font_size * relative_size
|
267
|
+
else
|
268
|
+
size * relative_size
|
269
|
+
end
|
241
270
|
end
|
242
271
|
if size.nil?
|
243
272
|
yield
|
244
273
|
else
|
245
|
-
@document.font_size(size)
|
274
|
+
@document.font_size(size, &block)
|
246
275
|
end
|
247
276
|
end
|
248
277
|
|
@@ -274,20 +303,31 @@ module Prawn
|
|
274
303
|
end
|
275
304
|
end
|
276
305
|
|
277
|
-
def
|
306
|
+
def fragment_measurements=(fragment)
|
278
307
|
apply_font_settings(fragment) do
|
279
|
-
fragment.width = @document.width_of(
|
280
|
-
|
308
|
+
fragment.width = @document.width_of(
|
309
|
+
fragment.text,
|
310
|
+
kerning: @kerning
|
311
|
+
)
|
281
312
|
fragment.line_height = @document.font.height
|
282
313
|
fragment.descender = @document.font.descender
|
283
314
|
fragment.ascender = @document.font.ascender
|
284
315
|
end
|
285
316
|
end
|
286
317
|
|
287
|
-
def
|
288
|
-
@max_line_height = [
|
289
|
-
|
290
|
-
|
318
|
+
def line_measurement_maximums=(fragment)
|
319
|
+
@max_line_height = [
|
320
|
+
defined?(@max_line_height) && @max_line_height,
|
321
|
+
fragment.line_height
|
322
|
+
].compact.max
|
323
|
+
@max_descender = [
|
324
|
+
defined?(@max_descender) && @max_descender,
|
325
|
+
fragment.descender
|
326
|
+
].compact.max
|
327
|
+
@max_ascender = [
|
328
|
+
defined?(@max_ascender) && @max_ascender,
|
329
|
+
fragment.ascender
|
330
|
+
].compact.max
|
291
331
|
end
|
292
332
|
end
|
293
333
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# text/formatted/rectangle.rb : Implements text boxes with formatted text
|
4
4
|
#
|
@@ -54,8 +54,8 @@ module Prawn
|
|
54
54
|
# a file or application to be opened locally. A clickable link will be
|
55
55
|
# created to the provided local file or application. If the file is
|
56
56
|
# another PDF, it will be opened in a new window. Note that you must
|
57
|
-
# explicitly underline and color using the appropriate tags if you
|
58
|
-
# to draw attention to the link
|
57
|
+
# explicitly underline and color using the appropriate tags if you
|
58
|
+
# which to draw attention to the link
|
59
59
|
# <tt>:draw_text_callback</tt>:
|
60
60
|
# if provided, this Proc will be called instead of #draw_text! once
|
61
61
|
# per fragment for every low-level addition of text to the page.
|
@@ -83,13 +83,14 @@ module Prawn
|
|
83
83
|
#
|
84
84
|
# == Exceptions
|
85
85
|
#
|
86
|
-
# Raises "Bad font family" if no font family is defined for the current
|
86
|
+
# Raises "Bad font family" if no font family is defined for the current
|
87
|
+
# font
|
87
88
|
#
|
88
89
|
# Raises <tt>Prawn::Errors::CannotFit</tt> if not wide enough to print
|
89
90
|
# any text
|
90
91
|
#
|
91
92
|
def formatted_text_box(array, options = {})
|
92
|
-
Text::Formatted::Box.new(array, options.merge(:
|
93
|
+
Text::Formatted::Box.new(array, options.merge(document: self)).render
|
93
94
|
end
|
94
95
|
|
95
96
|
# Generally, one would use the Prawn::Text::Formatted#formatted_text_box
|
@@ -137,37 +138,38 @@ module Prawn
|
|
137
138
|
# See Prawn::Text#text_box for valid options
|
138
139
|
#
|
139
140
|
def initialize(formatted_text, options = {})
|
140
|
-
@inked
|
141
|
+
@inked = false
|
141
142
|
Prawn.verify_options(valid_options, options)
|
142
|
-
options
|
143
|
+
options = options.dup
|
143
144
|
|
144
145
|
self.class.extensions.reverse_each { |e| extend e }
|
145
146
|
|
146
|
-
@overflow
|
147
|
+
@overflow = options[:overflow] || :truncate
|
147
148
|
@disable_wrap_by_char = options[:disable_wrap_by_char]
|
148
149
|
|
149
150
|
self.original_text = formatted_text
|
150
|
-
@text
|
151
|
-
|
152
|
-
@document
|
153
|
-
@direction
|
154
|
-
@fallback_fonts
|
155
|
-
|
156
|
-
@at
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
@
|
162
|
-
|
163
|
-
|
164
|
-
@
|
151
|
+
@text = nil
|
152
|
+
|
153
|
+
@document = options[:document]
|
154
|
+
@direction = options[:direction] || @document.text_direction
|
155
|
+
@fallback_fonts = options[:fallback_fonts] ||
|
156
|
+
@document.fallback_fonts
|
157
|
+
@at = (
|
158
|
+
options[:at] || [@document.bounds.left, @document.bounds.top]
|
159
|
+
).dup
|
160
|
+
@width = options[:width] ||
|
161
|
+
@document.bounds.right - @at[0]
|
162
|
+
@height = options[:height] || default_height
|
163
|
+
@align = options[:align] ||
|
164
|
+
(@direction == :rtl ? :right : :left)
|
165
|
+
@vertical_align = options[:valign] || :top
|
166
|
+
@leading = options[:leading] || @document.default_leading
|
165
167
|
@character_spacing = options[:character_spacing] ||
|
166
|
-
|
167
|
-
@mode
|
168
|
-
@rotate
|
169
|
-
@rotate_around
|
170
|
-
@single_line
|
168
|
+
@document.character_spacing
|
169
|
+
@mode = options[:mode] || @document.text_rendering_mode
|
170
|
+
@rotate = options[:rotate] || 0
|
171
|
+
@rotate_around = options[:rotate_around] || :upper_left
|
172
|
+
@single_line = options[:single_line]
|
171
173
|
@draw_text_callback = options[:draw_text_callback]
|
172
174
|
|
173
175
|
# if the text rendering mode is :unknown, force it back to :fill
|
@@ -183,25 +185,28 @@ module Prawn
|
|
183
185
|
@overflow = :truncate
|
184
186
|
end
|
185
187
|
@min_font_size = options[:min_font_size] || 5
|
186
|
-
if options[:kerning].nil?
|
188
|
+
if options[:kerning].nil?
|
187
189
|
options[:kerning] = @document.default_kerning?
|
188
190
|
end
|
189
|
-
@options = {
|
190
|
-
|
191
|
-
|
191
|
+
@options = {
|
192
|
+
kerning: options[:kerning],
|
193
|
+
size: options[:size],
|
194
|
+
style: options[:style]
|
195
|
+
}
|
192
196
|
|
193
197
|
super(formatted_text, options)
|
194
198
|
end
|
195
199
|
|
196
|
-
# Render text to the document based on the settings defined in
|
200
|
+
# Render text to the document based on the settings defined in
|
201
|
+
# initialize.
|
197
202
|
#
|
198
|
-
# In order to facilitate look-ahead calculations, <tt>render</tt>
|
199
|
-
# a <tt>:dry_run => true</tt> option. If provided, then
|
200
|
-
# executed as if rendering, with the exception that
|
201
|
-
# the page. Useful for look-ahead computations of
|
202
|
-
# etc.
|
203
|
+
# In order to facilitate look-ahead calculations, <tt>render</tt>
|
204
|
+
# accepts a <tt>:dry_run => true</tt> option. If provided, then
|
205
|
+
# everything is executed as if rendering, with the exception that
|
206
|
+
# nothing is drawn on the page. Useful for look-ahead computations of
|
207
|
+
# height, unprinted text, etc.
|
203
208
|
#
|
204
|
-
# Returns any text that did not print under the current settings
|
209
|
+
# Returns any text that did not print under the current settings.
|
205
210
|
#
|
206
211
|
def render(flags = {})
|
207
212
|
unprinted_text = []
|
@@ -217,11 +222,12 @@ module Prawn
|
|
217
222
|
shrink_to_fit(text) if @overflow == :shrink_to_fit
|
218
223
|
process_vertical_alignment(text)
|
219
224
|
@inked = true unless flags[:dry_run]
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
+
unprinted_text =
|
226
|
+
if @rotate != 0 && @inked
|
227
|
+
render_rotated(text)
|
228
|
+
else
|
229
|
+
wrap(text)
|
230
|
+
end
|
225
231
|
@inked = false
|
226
232
|
end
|
227
233
|
end
|
@@ -229,7 +235,7 @@ module Prawn
|
|
229
235
|
end
|
230
236
|
|
231
237
|
unprinted_text.map do |e|
|
232
|
-
e.merge(:
|
238
|
+
e.merge(text: @document.font.to_utf8(e[:text]))
|
233
239
|
end
|
234
240
|
end
|
235
241
|
|
@@ -243,13 +249,16 @@ module Prawn
|
|
243
249
|
#
|
244
250
|
def height
|
245
251
|
return 0 if @baseline_y.nil? || @descender.nil?
|
252
|
+
|
246
253
|
(@baseline_y - @descender).abs
|
247
254
|
end
|
248
255
|
|
249
256
|
# <tt>fragment</tt> is a Prawn::Text::Formatted::Fragment object
|
250
257
|
#
|
251
|
-
def draw_fragment(
|
252
|
-
|
258
|
+
def draw_fragment(
|
259
|
+
fragment, accumulated_width = 0, line_width = 0, word_spacing = 0
|
260
|
+
) #:nodoc:
|
261
|
+
case @align
|
253
262
|
when :left
|
254
263
|
x = @at[0]
|
255
264
|
when :center
|
@@ -257,11 +266,15 @@ module Prawn
|
|
257
266
|
when :right
|
258
267
|
x = @at[0] + @width - line_width
|
259
268
|
when :justify
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
269
|
+
x =
|
270
|
+
if @direction == :ltr
|
271
|
+
@at[0]
|
272
|
+
else
|
273
|
+
@at[0] + @width - line_width
|
274
|
+
end
|
275
|
+
else
|
276
|
+
raise ArgumentError,
|
277
|
+
'align must be one of :left, :right, :center or :justify symbols'
|
265
278
|
end
|
266
279
|
|
267
280
|
x += accumulated_width
|
@@ -276,15 +289,21 @@ module Prawn
|
|
276
289
|
if @inked
|
277
290
|
draw_fragment_underlays(fragment)
|
278
291
|
|
279
|
-
@document.word_spacing(word_spacing)
|
292
|
+
@document.word_spacing(word_spacing) do
|
280
293
|
if @draw_text_callback
|
281
|
-
@draw_text_callback.call(
|
282
|
-
|
294
|
+
@draw_text_callback.call(
|
295
|
+
fragment.text,
|
296
|
+
at: [x, y],
|
297
|
+
kerning: @kerning
|
298
|
+
)
|
283
299
|
else
|
284
|
-
@document.draw_text!(
|
285
|
-
|
300
|
+
@document.draw_text!(
|
301
|
+
fragment.text,
|
302
|
+
at: [x, y],
|
303
|
+
kerning: @kerning
|
304
|
+
)
|
286
305
|
end
|
287
|
-
|
306
|
+
end
|
288
307
|
|
289
308
|
draw_fragment_overlays(fragment)
|
290
309
|
end
|
@@ -325,23 +344,24 @@ module Prawn
|
|
325
344
|
|
326
345
|
# @private
|
327
346
|
def self.inherited(base)
|
347
|
+
super
|
328
348
|
extensions.each { |e| base.extensions << e }
|
329
349
|
end
|
330
350
|
|
331
351
|
def valid_options
|
332
|
-
PDF::Core::Text::VALID_OPTIONS + [
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
352
|
+
PDF::Core::Text::VALID_OPTIONS + %i[
|
353
|
+
at
|
354
|
+
height width
|
355
|
+
align valign
|
356
|
+
rotate rotate_around
|
357
|
+
overflow min_font_size
|
358
|
+
disable_wrap_by_char
|
359
|
+
leading character_spacing
|
360
|
+
mode single_line
|
361
|
+
document
|
362
|
+
direction
|
363
|
+
fallback_fonts
|
364
|
+
draw_text_callback
|
345
365
|
]
|
346
366
|
end
|
347
367
|
|
@@ -356,7 +376,7 @@ module Prawn
|
|
356
376
|
end
|
357
377
|
|
358
378
|
def original_text
|
359
|
-
@original_array.
|
379
|
+
@original_array.map(&:dup)
|
360
380
|
end
|
361
381
|
|
362
382
|
def original_text=(formatted_text)
|
@@ -407,10 +427,14 @@ module Prawn
|
|
407
427
|
|
408
428
|
@document.save_font do
|
409
429
|
hash[:text].each_char do |char|
|
410
|
-
font_glyph_pairs << [
|
411
|
-
|
412
|
-
|
413
|
-
|
430
|
+
font_glyph_pairs << [
|
431
|
+
find_font_for_this_glyph(
|
432
|
+
char,
|
433
|
+
fragment_font,
|
434
|
+
fallback_fonts.dup
|
435
|
+
),
|
436
|
+
char
|
437
|
+
]
|
414
438
|
end
|
415
439
|
end
|
416
440
|
|
@@ -426,7 +450,7 @@ module Prawn
|
|
426
450
|
|
427
451
|
def find_font_for_this_glyph(char, current_font, fallback_fonts)
|
428
452
|
@document.font(current_font)
|
429
|
-
if fallback_fonts.
|
453
|
+
if fallback_fonts.empty? || @document.font.glyph_present?(char)
|
430
454
|
current_font
|
431
455
|
else
|
432
456
|
find_font_for_this_glyph(char, fallback_fonts.shift, fallback_fonts)
|
@@ -439,7 +463,7 @@ module Prawn
|
|
439
463
|
current_font = nil
|
440
464
|
|
441
465
|
font_glyph_pairs.each do |font, char|
|
442
|
-
if font != current_font || fragments.count
|
466
|
+
if font != current_font || fragments.count.zero?
|
443
467
|
current_font = font
|
444
468
|
fragment = hash.dup
|
445
469
|
fragment[:text] = char
|
@@ -454,8 +478,8 @@ module Prawn
|
|
454
478
|
end
|
455
479
|
|
456
480
|
def move_baseline_down
|
457
|
-
if @baseline_y
|
458
|
-
@baseline_y
|
481
|
+
if @baseline_y.zero?
|
482
|
+
@baseline_y = -@ascender
|
459
483
|
else
|
460
484
|
@baseline_y -= (@line_height + @leading)
|
461
485
|
end
|
@@ -479,7 +503,11 @@ module Prawn
|
|
479
503
|
# we need to wait until render() is called so that the fonts are set
|
480
504
|
# up properly for wrapping. So guard with a boolean to ensure this is
|
481
505
|
# only run once.
|
482
|
-
|
506
|
+
if defined?(@vertical_alignment_processed) &&
|
507
|
+
@vertical_alignment_processed
|
508
|
+
return
|
509
|
+
end
|
510
|
+
|
483
511
|
@vertical_alignment_processed = true
|
484
512
|
|
485
513
|
return if @vertical_align == :top
|
@@ -523,7 +551,7 @@ module Prawn
|
|
523
551
|
# document.process_text_options sets the font
|
524
552
|
@document.process_text_options(@options)
|
525
553
|
@font_size = @options[:size]
|
526
|
-
@kerning
|
554
|
+
@kerning = @options[:kerning]
|
527
555
|
end
|
528
556
|
|
529
557
|
def render_rotated(text)
|
@@ -547,7 +575,7 @@ module Prawn
|
|
547
575
|
y = @at[1]
|
548
576
|
end
|
549
577
|
|
550
|
-
@document.rotate(@rotate, :
|
578
|
+
@document.rotate(@rotate, origin: [x, y]) do
|
551
579
|
unprinted_text = wrap(text)
|
552
580
|
end
|
553
581
|
unprinted_text
|
@@ -571,41 +599,52 @@ module Prawn
|
|
571
599
|
|
572
600
|
def draw_fragment_overlay_link(fragment)
|
573
601
|
return unless fragment.link
|
602
|
+
|
574
603
|
box = fragment.absolute_bounding_box
|
575
|
-
@document.link_annotation(
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
604
|
+
@document.link_annotation(
|
605
|
+
box,
|
606
|
+
Border: [0, 0, 0],
|
607
|
+
A: {
|
608
|
+
Type: :Action,
|
609
|
+
S: :URI,
|
610
|
+
URI: PDF::Core::LiteralString.new(fragment.link)
|
611
|
+
}
|
612
|
+
)
|
580
613
|
end
|
581
614
|
|
582
615
|
def draw_fragment_overlay_anchor(fragment)
|
583
616
|
return unless fragment.anchor
|
617
|
+
|
584
618
|
box = fragment.absolute_bounding_box
|
585
|
-
@document.link_annotation(
|
586
|
-
|
587
|
-
|
619
|
+
@document.link_annotation(
|
620
|
+
box,
|
621
|
+
Border: [0, 0, 0],
|
622
|
+
Dest: fragment.anchor
|
623
|
+
)
|
588
624
|
end
|
589
625
|
|
590
626
|
def draw_fragment_overlay_local(fragment)
|
591
627
|
return unless fragment.local
|
628
|
+
|
592
629
|
box = fragment.absolute_bounding_box
|
593
|
-
@document.link_annotation(
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
630
|
+
@document.link_annotation(
|
631
|
+
box,
|
632
|
+
Border: [0, 0, 0],
|
633
|
+
A: {
|
634
|
+
Type: :Action,
|
635
|
+
S: :Launch,
|
636
|
+
F: PDF::Core::LiteralString.new(fragment.local),
|
637
|
+
NewWindow: true
|
638
|
+
}
|
639
|
+
)
|
599
640
|
end
|
600
641
|
|
601
642
|
def draw_fragment_overlay_styles(fragment)
|
602
|
-
|
603
|
-
if underline
|
643
|
+
if fragment.styles.include?(:underline)
|
604
644
|
@document.stroke_line(fragment.underline_points)
|
605
645
|
end
|
606
646
|
|
607
|
-
|
608
|
-
if strikethrough
|
647
|
+
if fragment.styles.include?(:strikethrough)
|
609
648
|
@document.stroke_line(fragment.strikethrough_points)
|
610
649
|
end
|
611
650
|
end
|