prawn 2.3.0 → 2.5.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 (203) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/prawn/document/bounding_box.rb +223 -143
  4. data/lib/prawn/document/column_box.rb +61 -26
  5. data/lib/prawn/document/internals.rb +25 -16
  6. data/lib/prawn/document/span.rb +21 -18
  7. data/lib/prawn/document.rb +273 -182
  8. data/lib/prawn/encoding.rb +2 -5
  9. data/lib/prawn/errors.rb +23 -34
  10. data/lib/prawn/font.rb +254 -139
  11. data/lib/prawn/font_metric_cache.rb +18 -16
  12. data/lib/prawn/fonts/afm.rb +99 -57
  13. data/lib/prawn/fonts/dfont.rb +7 -1
  14. data/lib/prawn/fonts/otf.rb +4 -1
  15. data/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
  16. data/lib/prawn/fonts/ttc.rb +7 -2
  17. data/lib/prawn/fonts/ttf.rb +345 -107
  18. data/lib/prawn/fonts.rb +14 -0
  19. data/lib/prawn/graphics/blend_mode.rb +25 -28
  20. data/lib/prawn/graphics/cap_style.rb +9 -12
  21. data/lib/prawn/graphics/color.rb +75 -50
  22. data/lib/prawn/graphics/dash.rb +45 -42
  23. data/lib/prawn/graphics/join_style.rb +18 -12
  24. data/lib/prawn/graphics/patterns.rb +239 -110
  25. data/lib/prawn/graphics/transformation.rb +51 -44
  26. data/lib/prawn/graphics/transparency.rb +16 -40
  27. data/lib/prawn/graphics.rb +370 -260
  28. data/lib/prawn/grid.rb +219 -57
  29. data/lib/prawn/image_handler.rb +27 -10
  30. data/lib/prawn/images/image.rb +8 -10
  31. data/lib/prawn/images/jpg.rb +46 -20
  32. data/lib/prawn/images/png.rb +94 -42
  33. data/lib/prawn/images.rb +70 -81
  34. data/lib/prawn/measurement_extensions.rb +39 -8
  35. data/lib/prawn/measurements.rb +60 -5
  36. data/lib/prawn/outline.rb +120 -113
  37. data/lib/prawn/repeater.rb +52 -36
  38. data/lib/prawn/security/arcfour.rb +4 -4
  39. data/lib/prawn/security.rb +106 -98
  40. data/lib/prawn/soft_mask.rb +42 -30
  41. data/lib/prawn/stamp.rb +38 -42
  42. data/lib/prawn/text/box.rb +156 -105
  43. data/lib/prawn/text/formatted/arranger.rb +121 -41
  44. data/lib/prawn/text/formatted/box.rb +239 -163
  45. data/lib/prawn/text/formatted/fragment.rb +130 -14
  46. data/lib/prawn/text/formatted/line_wrap.rb +49 -38
  47. data/lib/prawn/text/formatted/parser.rb +116 -74
  48. data/lib/prawn/text/formatted/wrap.rb +25 -26
  49. data/lib/prawn/text/formatted.rb +75 -0
  50. data/lib/prawn/text.rb +456 -211
  51. data/lib/prawn/transformation_stack.rb +29 -10
  52. data/lib/prawn/utilities.rb +13 -13
  53. data/lib/prawn/version.rb +2 -1
  54. data/lib/prawn/view.rb +69 -54
  55. data/lib/prawn.rb +24 -18
  56. data.tar.gz.sig +0 -0
  57. metadata +55 -262
  58. metadata.gz.sig +3 -4
  59. data/.yardopts +0 -10
  60. data/Gemfile +0 -5
  61. data/Rakefile +0 -54
  62. data/manual/absolute_position.pdf +0 -0
  63. data/manual/basic_concepts/adding_pages.rb +0 -26
  64. data/manual/basic_concepts/basic_concepts.rb +0 -43
  65. data/manual/basic_concepts/creation.rb +0 -38
  66. data/manual/basic_concepts/cursor.rb +0 -32
  67. data/manual/basic_concepts/measurement.rb +0 -24
  68. data/manual/basic_concepts/origin.rb +0 -37
  69. data/manual/basic_concepts/other_cursor_helpers.rb +0 -39
  70. data/manual/basic_concepts/view.rb +0 -48
  71. data/manual/bounding_box/bounding_box.rb +0 -41
  72. data/manual/bounding_box/bounds.rb +0 -48
  73. data/manual/bounding_box/canvas.rb +0 -23
  74. data/manual/bounding_box/creation.rb +0 -22
  75. data/manual/bounding_box/indentation.rb +0 -45
  76. data/manual/bounding_box/nesting.rb +0 -52
  77. data/manual/bounding_box/russian_boxes.rb +0 -40
  78. data/manual/bounding_box/stretchy.rb +0 -29
  79. data/manual/contents.rb +0 -35
  80. data/manual/cover.rb +0 -43
  81. data/manual/document_and_page_options/background.rb +0 -25
  82. data/manual/document_and_page_options/document_and_page_options.rb +0 -34
  83. data/manual/document_and_page_options/metadata.rb +0 -25
  84. data/manual/document_and_page_options/page_margins.rb +0 -36
  85. data/manual/document_and_page_options/page_size.rb +0 -34
  86. data/manual/document_and_page_options/print_scaling.rb +0 -22
  87. data/manual/example_helper.rb +0 -8
  88. data/manual/graphics/blend_mode.rb +0 -52
  89. data/manual/graphics/circle_and_ellipse.rb +0 -21
  90. data/manual/graphics/color.rb +0 -22
  91. data/manual/graphics/common_lines.rb +0 -29
  92. data/manual/graphics/fill_and_stroke.rb +0 -41
  93. data/manual/graphics/fill_rules.rb +0 -37
  94. data/manual/graphics/gradients.rb +0 -43
  95. data/manual/graphics/graphics.rb +0 -64
  96. data/manual/graphics/helper.rb +0 -27
  97. data/manual/graphics/line_width.rb +0 -36
  98. data/manual/graphics/lines_and_curves.rb +0 -40
  99. data/manual/graphics/polygon.rb +0 -27
  100. data/manual/graphics/rectangle.rb +0 -20
  101. data/manual/graphics/rotate.rb +0 -25
  102. data/manual/graphics/scale.rb +0 -42
  103. data/manual/graphics/soft_masks.rb +0 -44
  104. data/manual/graphics/stroke_cap.rb +0 -30
  105. data/manual/graphics/stroke_dash.rb +0 -47
  106. data/manual/graphics/stroke_join.rb +0 -29
  107. data/manual/graphics/translate.rb +0 -28
  108. data/manual/graphics/transparency.rb +0 -33
  109. data/manual/how_to_read_this_manual.rb +0 -39
  110. data/manual/images/absolute_position.rb +0 -22
  111. data/manual/images/fit.rb +0 -20
  112. data/manual/images/horizontal.rb +0 -24
  113. data/manual/images/images.rb +0 -41
  114. data/manual/images/plain_image.rb +0 -17
  115. data/manual/images/scale.rb +0 -21
  116. data/manual/images/vertical.rb +0 -27
  117. data/manual/images/width_and_height.rb +0 -24
  118. data/manual/layout/boxes.rb +0 -26
  119. data/manual/layout/content.rb +0 -24
  120. data/manual/layout/layout.rb +0 -27
  121. data/manual/layout/simple_grid.rb +0 -22
  122. data/manual/outline/add_subsection_to.rb +0 -60
  123. data/manual/outline/insert_section_after.rb +0 -46
  124. data/manual/outline/outline.rb +0 -33
  125. data/manual/outline/sections_and_pages.rb +0 -66
  126. data/manual/repeatable_content/alternate_page_numbering.rb +0 -36
  127. data/manual/repeatable_content/page_numbering.rb +0 -55
  128. data/manual/repeatable_content/repeatable_content.rb +0 -35
  129. data/manual/repeatable_content/repeater.rb +0 -54
  130. data/manual/repeatable_content/stamp.rb +0 -40
  131. data/manual/security/encryption.rb +0 -28
  132. data/manual/security/permissions.rb +0 -41
  133. data/manual/security/security.rb +0 -28
  134. data/manual/table.rb +0 -16
  135. data/manual/text/alignment.rb +0 -43
  136. data/manual/text/color.rb +0 -24
  137. data/manual/text/column_box.rb +0 -30
  138. data/manual/text/fallback_fonts.rb +0 -41
  139. data/manual/text/font.rb +0 -40
  140. data/manual/text/font_size.rb +0 -44
  141. data/manual/text/font_style.rb +0 -22
  142. data/manual/text/formatted_callbacks.rb +0 -65
  143. data/manual/text/formatted_text.rb +0 -58
  144. data/manual/text/free_flowing_text.rb +0 -50
  145. data/manual/text/inline.rb +0 -40
  146. data/manual/text/kerning_and_character_spacing.rb +0 -38
  147. data/manual/text/leading.rb +0 -24
  148. data/manual/text/line_wrapping.rb +0 -60
  149. data/manual/text/paragraph_indentation.rb +0 -32
  150. data/manual/text/positioned_text.rb +0 -37
  151. data/manual/text/registering_families.rb +0 -51
  152. data/manual/text/rendering_and_color.rb +0 -36
  153. data/manual/text/right_to_left_text.rb +0 -54
  154. data/manual/text/rotation.rb +0 -47
  155. data/manual/text/single_usage.rb +0 -36
  156. data/manual/text/text.rb +0 -75
  157. data/manual/text/text_box_excess.rb +0 -35
  158. data/manual/text/text_box_extensions.rb +0 -48
  159. data/manual/text/text_box_overflow.rb +0 -49
  160. data/manual/text/utf8.rb +0 -27
  161. data/manual/text/win_ansi_charset.rb +0 -62
  162. data/prawn.gemspec +0 -57
  163. data/spec/data/curves.pdf +0 -66
  164. data/spec/extensions/encoding_helpers.rb +0 -11
  165. data/spec/prawn/document/bounding_box_spec.rb +0 -546
  166. data/spec/prawn/document/column_box_spec.rb +0 -75
  167. data/spec/prawn/document/security_spec.rb +0 -176
  168. data/spec/prawn/document_annotations_spec.rb +0 -76
  169. data/spec/prawn/document_destinations_spec.rb +0 -15
  170. data/spec/prawn/document_grid_spec.rb +0 -99
  171. data/spec/prawn/document_reference_spec.rb +0 -27
  172. data/spec/prawn/document_span_spec.rb +0 -36
  173. data/spec/prawn/document_spec.rb +0 -802
  174. data/spec/prawn/font_metric_cache_spec.rb +0 -54
  175. data/spec/prawn/font_spec.rb +0 -542
  176. data/spec/prawn/graphics/blend_mode_spec.rb +0 -63
  177. data/spec/prawn/graphics/transparency_spec.rb +0 -81
  178. data/spec/prawn/graphics_spec.rb +0 -837
  179. data/spec/prawn/graphics_stroke_styles_spec.rb +0 -229
  180. data/spec/prawn/image_handler_spec.rb +0 -53
  181. data/spec/prawn/images/jpg_spec.rb +0 -20
  182. data/spec/prawn/images/png_spec.rb +0 -283
  183. data/spec/prawn/images_spec.rb +0 -224
  184. data/spec/prawn/measurements_extensions_spec.rb +0 -24
  185. data/spec/prawn/outline_spec.rb +0 -412
  186. data/spec/prawn/repeater_spec.rb +0 -165
  187. data/spec/prawn/soft_mask_spec.rb +0 -74
  188. data/spec/prawn/stamp_spec.rb +0 -172
  189. data/spec/prawn/text/box_spec.rb +0 -1112
  190. data/spec/prawn/text/formatted/arranger_spec.rb +0 -466
  191. data/spec/prawn/text/formatted/box_spec.rb +0 -846
  192. data/spec/prawn/text/formatted/fragment_spec.rb +0 -343
  193. data/spec/prawn/text/formatted/line_wrap_spec.rb +0 -494
  194. data/spec/prawn/text/formatted/parser_spec.rb +0 -697
  195. data/spec/prawn/text_draw_text_spec.rb +0 -149
  196. data/spec/prawn/text_rendering_mode_spec.rb +0 -48
  197. data/spec/prawn/text_spacing_spec.rb +0 -95
  198. data/spec/prawn/text_spec.rb +0 -603
  199. data/spec/prawn/text_with_inline_formatting_spec.rb +0 -35
  200. data/spec/prawn/transformation_stack_spec.rb +0 -66
  201. data/spec/prawn/view_spec.rb +0 -63
  202. data/spec/prawn_manual_spec.rb +0 -35
  203. data/spec/spec_helper.rb +0 -48
@@ -1,140 +1,191 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # text/rectangle.rb : Implements text boxes
4
- #
5
- # Copyright November 2009, Daniel Nelson. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- #
9
-
10
3
  require_relative 'formatted/box'
11
4
 
12
5
  module Prawn
13
- module Text
6
+ module Text # rubocop: disable Style/Documentation
14
7
  # @group Stable API
15
8
 
16
- # Draws the requested text into a box. When the text overflows
17
- # the rectangle, you shrink to fit, or truncate the text. Text
18
- # boxes are independent of the document y position.
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.
19
13
  #
20
- # == Encoding
14
+ # #### Encoding
21
15
  #
22
- # Note that strings passed to this function should be encoded as UTF-8.
23
- # If you get unexpected characters appearing in your rendered document,
24
- # check this.
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.
25
19
  #
26
- # If the current font is a built-in one, although the string must be
27
- # encoded as UTF-8, only characters that are available in WinAnsi
28
- # are allowed.
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.
29
22
  #
30
23
  # If an empty box is rendered to your PDF instead of the character you
31
24
  # wanted it usually means the current font doesn't include that character.
32
25
  #
33
- # == Options (default values marked in [])
34
- #
35
- # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
36
- # is available with the current font)
37
- # [value of document.default_kerning?]
38
- # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
39
- # size]
40
- # <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
41
- # to or remove from the default character
42
- # spacing. [0]
43
- # <tt>:disable_wrap_by_char</tt>:: <tt>boolean</tt> Whether
44
- # or not to prevent mid-word breaks when text does not fit in box. [false]
45
- # <tt>:mode</tt>:: <tt>symbol</tt>. The text rendering mode. See
46
- # documentation for Prawn::Document#text_rendering_mode
47
- # for a list of valid options. [:fill]
48
- # <tt>:style</tt>:: The style to use. The requested style must be part of
49
- # the current font familly. [current style]
50
- #
51
- # <tt>:at</tt>::
52
- # <tt>[x, y]</tt>. The upper left corner of the box
53
- # [@document.bounds.left, @document.bounds.top]
54
- # <tt>:width</tt>::
55
- # <tt>number</tt>. The width of the box
56
- # [@document.bounds.right - @at[0]]
57
- # <tt>:height</tt>::
58
- # <tt>number</tt>. The height of the box [default_height()]
59
- # <tt>:direction</tt>::
60
- # <tt>:ltr</tt>, <tt>:rtl</tt>, Direction of the text (left-to-right
61
- # or right-to-left) [value of document.text_direction]
62
- # <tt>:fallback_fonts</tt>::
63
- # An array of font names. Each name must be the name of an AFM font or
64
- # the name that was used to register a family of external fonts (see
65
- # Prawn::Document#font_families). If present, then each glyph will be
66
- # rendered using the first font that includes the glyph, starting with
67
- # the current font and then moving through :fallback_fonts from
68
- # left to right.
69
- # <tt>:align</tt>::
70
- # <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>, or
71
- # <tt>:justify</tt> Alignment within the bounding box
72
- # [:left if direction is :ltr, :right if direction is :rtl]
73
- # <tt>:valign</tt>::
74
- # <tt>:top</tt>, <tt>:center</tt>, or <tt>:bottom</tt>. Vertical
75
- # alignment within the bounding box [:top]
76
- # <tt>:rotate</tt>::
77
- # <tt>number</tt>. The angle to rotate the text
78
- # <tt>:rotate_around</tt>::
79
- # <tt>:center</tt>, <tt>:upper_left</tt>, <tt>:upper_right</tt>,
80
- # <tt>:lower_right</tt>, or <tt>:lower_left</tt>. The point around which
81
- # to rotate the text [:upper_left]
82
- # <tt>:leading</tt>::
83
- # <tt>number</tt>. Additional space between lines [value of
84
- # document.default_leading]
85
- # <tt>:single_line</tt>::
86
- # <tt>boolean</tt>. If true, then only the first line will be drawn
87
- # [false]
88
- # <tt>:overflow</tt>::
89
- # <tt>:truncate</tt>, <tt>:shrink_to_fit</tt>, or <tt>:expand</tt>
90
- # This controls the behavior when the amount of text
91
- # exceeds the available space. [:truncate]
92
- # <tt>:min_font_size</tt>::
93
- # <tt>number</tt>. The minimum font size to use when :overflow is set to
94
- # :shrink_to_fit (that is the font size will not be reduced to less than
95
- # this value, even if it means that some text will be cut off). [5]
96
- #
97
- # == Returns
98
- #
99
- # Returns any text that did not print under the current settings.
100
- #
101
- # == Exceptions
102
- #
103
- # Raises <tt>Prawn::Errors::CannotFit</tt> if not wide enough to print
104
- # any text
105
- #
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.
106
83
  def text_box(string, options = {})
107
84
  options = options.dup
108
85
  options[:document] = self
109
86
 
110
- box = if options[:inline_format]
111
- p = options.delete(:inline_format)
112
- p = [] unless p.is_a?(Array)
113
- array = text_formatter.format(string, *p)
114
- Text::Formatted::Box.new(array, options)
115
- else
116
- Text::Box.new(string, options)
117
- end
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
118
96
 
119
97
  box.render
120
98
  end
121
99
 
122
100
  # @group Experimental API
123
101
 
124
- # Generally, one would use the Prawn::Text#text_box convenience
125
- # method. However, using Text::Box.new in conjunction with
126
- # #render(:dry_run=> true) enables one to do look-ahead calculations prior
127
- # to placing text on the page, or to determine how much vertical space was
128
- # consumed by the printed text
102
+ # Text box.
129
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.
130
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).
131
165
  def initialize(string, options = {})
132
166
  super([{ text: string }], options)
133
167
  end
134
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.
135
186
  def render(flags = {})
136
187
  leftover = super(flags)
137
- leftover.collect { |hash| hash[:text] }.join
188
+ leftover.map { |hash| hash[:text] }.join
138
189
  end
139
190
  end
140
191
  end
@@ -1,18 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # core/text/formatted/arranger.rb : Implements a data structure for 2-stage
4
- # processing of lines of formatted text
5
- #
6
- # Copyright February 2010, Daniel Nelson. All Rights Reserved.
7
- #
8
- # This is free software. Please see the LICENSE and COPYING files for details.
9
-
10
3
  module Prawn
11
4
  module Text
12
- module Formatted #:nodoc:
5
+ module Formatted
6
+ # D data structure for 2-stage processing of lines of formatted text.
13
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
14
33
 
15
- class Arranger #:nodoc:
16
34
  attr_reader :max_line_height
17
35
  attr_reader :max_descender
18
36
  attr_reader :max_ascender
@@ -31,39 +49,55 @@ module Prawn
31
49
  @kerning = options[:kerning]
32
50
  end
33
51
 
52
+ # Number of spaces in the text.
53
+ #
54
+ # @return [Integer]
55
+ # @raise [NotFinalized]
34
56
  def space_count
35
57
  unless finalized
36
- raise 'Lines must be finalized before calling #space_count'
58
+ raise NotFinalized.new(method: 'space_count')
37
59
  end
38
60
 
39
- @fragments.inject(0) do |sum, fragment|
61
+ @fragments.reduce(0) do |sum, fragment|
40
62
  sum + fragment.space_count
41
63
  end
42
64
  end
43
65
 
66
+ # Line width.
67
+ #
68
+ # @return [Number]
69
+ # @raise [NotFinalized]
44
70
  def line_width
45
71
  unless finalized
46
- raise 'Lines must be finalized before calling #line_width'
72
+ raise raise NotFinalized.new(method: 'line_width')
47
73
  end
48
74
 
49
- @fragments.inject(0) do |sum, fragment|
75
+ @fragments.reduce(0) do |sum, fragment|
50
76
  sum + fragment.width
51
77
  end
52
78
  end
53
79
 
80
+ # Line text.
81
+ #
82
+ # @return [String]
83
+ # @raise [NotFinalized]
54
84
  def line
55
85
  unless finalized
56
- raise 'Lines must be finalized before calling #line'
86
+ raise NotFinalized.new(method: 'line')
57
87
  end
58
88
 
59
- @fragments.collect do |fragment|
60
- fragment.text.dup.encode(::Encoding::UTF_8)
61
- rescue ::Encoding::InvalidByteSequenceError,
62
- ::Encoding::UndefinedConversionError
63
- fragment.text.dup.force_encoding(::Encoding::UTF_8)
64
- end.join
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
65
96
  end
66
97
 
98
+ # Finish laying out current line.
99
+ #
100
+ # @return [void]
67
101
  def finalize_line
68
102
  @finalized = true
69
103
 
@@ -76,7 +110,7 @@ module Prawn
76
110
  fragment = Prawn::Text::Formatted::Fragment.new(
77
111
  text,
78
112
  format_state,
79
- @document
113
+ @document,
80
114
  )
81
115
  @fragments << fragment
82
116
  self.fragment_measurements = fragment
@@ -84,6 +118,10 @@ module Prawn
84
118
  end
85
119
  end
86
120
 
121
+ # Set new fragment array.
122
+ #
123
+ # @param array [Array<Hash>]
124
+ # @return [void]
87
125
  def format_array=(array)
88
126
  initialize_line
89
127
  @unconsumed = []
@@ -94,6 +132,9 @@ module Prawn
94
132
  end
95
133
  end
96
134
 
135
+ # Prepare for new line layout.
136
+ #
137
+ # @return [void]
97
138
  def initialize_line
98
139
  @finalized = false
99
140
  @max_line_height = 0
@@ -104,13 +145,20 @@ module Prawn
104
145
  @fragments = []
105
146
  end
106
147
 
148
+ # Were all fragments processed?
149
+ #
150
+ # @return [Boolean]
107
151
  def finished?
108
152
  @unconsumed.empty?
109
153
  end
110
154
 
155
+ # Get the next unprocessed string.
156
+ #
157
+ # @return [String, nil]
158
+ # @raise [NotFinalized]
111
159
  def next_string
112
160
  if finalized
113
- raise 'Lines must not be finalized when calling #next_string'
161
+ raise NotFinalized.new(method: 'next_string')
114
162
  end
115
163
 
116
164
  next_unconsumed_hash = @unconsumed.shift
@@ -124,6 +172,9 @@ module Prawn
124
172
  end
125
173
  end
126
174
 
175
+ # Get the next unprocessed string keeping it in the queue.
176
+ #
177
+ # @return [String, nil]
127
178
  def preview_next_string
128
179
  next_unconsumed_hash = @unconsumed.first
129
180
 
@@ -132,6 +183,11 @@ module Prawn
132
183
  end
133
184
  end
134
185
 
186
+ # Apply color and font settings.
187
+ #
188
+ # @param fragment [Prawn::Text::Formatted::Fragment]
189
+ # @yield
190
+ # @return [void]
135
191
  def apply_color_and_font_settings(fragment, &block)
136
192
  if fragment.color
137
193
  original_fill_color = @document.fill_color
@@ -146,6 +202,11 @@ module Prawn
146
202
  end
147
203
  end
148
204
 
205
+ # Apply font settings.
206
+ #
207
+ # @param fragment [Prawn::Text::Formatted::Fragment]
208
+ # @yield
209
+ # @return [void]
149
210
  def apply_font_settings(fragment = nil, &block)
150
211
  if fragment.nil?
151
212
  font = current_format_state[:font]
@@ -163,10 +224,10 @@ module Prawn
163
224
 
164
225
  @document.character_spacing(character_spacing) do
165
226
  if font || font_style != :normal
166
- raise 'Bad font family' unless @document.font.family
227
+ raise BadFontFamily unless @document.font.family
167
228
 
168
229
  @document.font(
169
- font || @document.font.family, style: font_style
230
+ font || @document.font.family, style: font_style,
170
231
  ) do
171
232
  apply_font_size(size, styles, &block)
172
233
  end
@@ -176,6 +237,12 @@ module Prawn
176
237
  end
177
238
  end
178
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]
179
246
  def update_last_string(printed, unprinted, normalized_soft_hyphen = nil)
180
247
  return if printed.nil?
181
248
 
@@ -195,14 +262,21 @@ module Prawn
195
262
  load_previous_format_state if printed.empty?
196
263
  end
197
264
 
265
+ # Get the next fragment.
266
+ #
267
+ # @return [Prawn::Text::Formatted::Fragment]
268
+ # @raise [NotFinalized]
198
269
  def retrieve_fragment
199
270
  unless finalized
200
- raise 'Lines must be finalized before fragments can be retrieved'
271
+ raise NotFinalized, 'Lines must be finalized before fragments can be retrieved'
201
272
  end
202
273
 
203
274
  @fragments.shift
204
275
  end
205
276
 
277
+ # Repack remaining fragments.
278
+ #
279
+ # @return [void]
206
280
  def repack_unretrieved
207
281
  new_unconsumed = []
208
282
  # rubocop: disable Lint/AssignmentInCondition
@@ -214,10 +288,13 @@ module Prawn
214
288
  @unconsumed = new_unconsumed.concat(@unconsumed)
215
289
  end
216
290
 
291
+ # Get font variant from fragment styles.
292
+ #
293
+ # @param styles [Array<Symbol>]
294
+ # @return [Symbol]
217
295
  def font_style(styles)
218
- if styles.nil?
219
- :normal
220
- elsif styles.include?(:bold) && styles.include?(:italic)
296
+ styles = Array(styles)
297
+ if styles.include?(:bold) && styles.include?(:italic)
221
298
  :bold_italic
222
299
  elsif styles.include?(:bold)
223
300
  :bold
@@ -240,31 +317,34 @@ module Prawn
240
317
  end
241
318
  end
242
319
 
243
- def apply_font_size(size, styles)
320
+ def apply_font_size(size, styles, &block)
244
321
  if subscript?(styles) || superscript?(styles)
245
322
  relative_size = 0.583
246
- size = if size.nil?
247
- @document.font_size * relative_size
248
- else
249
- size * relative_size
250
- end
323
+ size =
324
+ if size.nil?
325
+ @document.font_size * relative_size
326
+ else
327
+ size * relative_size
328
+ end
251
329
  end
252
330
  if size.nil?
253
331
  yield
254
332
  else
255
- @document.font_size(size) { yield }
333
+ @document.font_size(size, &block)
256
334
  end
257
335
  end
258
336
 
259
337
  def subscript?(styles)
260
338
  if styles.nil? then false
261
- else styles.include?(:subscript)
339
+ else
340
+ styles.include?(:subscript)
262
341
  end
263
342
  end
264
343
 
265
344
  def superscript?(styles)
266
345
  if styles.nil? then false
267
- else styles.include?(:superscript)
346
+ else
347
+ styles.include?(:superscript)
268
348
  end
269
349
  end
270
350
 
@@ -288,7 +368,7 @@ module Prawn
288
368
  apply_font_settings(fragment) do
289
369
  fragment.width = @document.width_of(
290
370
  fragment.text,
291
- kerning: @kerning
371
+ kerning: @kerning,
292
372
  )
293
373
  fragment.line_height = @document.font.height
294
374
  fragment.descender = @document.font.descender
@@ -299,15 +379,15 @@ module Prawn
299
379
  def line_measurement_maximums=(fragment)
300
380
  @max_line_height = [
301
381
  defined?(@max_line_height) && @max_line_height,
302
- fragment.line_height
382
+ fragment.line_height,
303
383
  ].compact.max
304
384
  @max_descender = [
305
385
  defined?(@max_descender) && @max_descender,
306
- fragment.descender
386
+ fragment.descender,
307
387
  ].compact.max
308
388
  @max_ascender = [
309
389
  defined?(@max_ascender) && @max_ascender,
310
- fragment.ascender
390
+ fragment.ascender,
311
391
  ].compact.max
312
392
  end
313
393
  end