prawn 1.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.
Files changed (309) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +1 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +9 -40
  7. data/lib/prawn/document/bounding_box.rb +54 -40
  8. data/lib/prawn/document/column_box.rb +8 -10
  9. data/lib/prawn/document/internals.rb +39 -146
  10. data/lib/prawn/document/span.rb +23 -17
  11. data/lib/prawn/document.rb +217 -182
  12. data/lib/prawn/encoding.rb +69 -101
  13. data/lib/prawn/errors.rb +47 -43
  14. data/lib/prawn/font.rb +124 -104
  15. data/lib/prawn/font_metric_cache.rb +23 -21
  16. data/lib/prawn/fonts/afm.rb +292 -0
  17. data/lib/prawn/{font → fonts}/dfont.rb +5 -12
  18. data/lib/prawn/fonts/otf.rb +11 -0
  19. data/lib/prawn/fonts/ttc.rb +36 -0
  20. data/lib/prawn/{font → fonts}/ttf.rb +140 -88
  21. data/lib/prawn/graphics/blend_mode.rb +65 -0
  22. data/lib/prawn/graphics/cap_style.rb +5 -5
  23. data/lib/prawn/graphics/color.rb +46 -44
  24. data/lib/prawn/graphics/dash.rb +27 -11
  25. data/lib/prawn/graphics/join_style.rb +11 -6
  26. data/lib/prawn/graphics/patterns.rb +220 -78
  27. data/lib/prawn/graphics/transformation.rb +20 -12
  28. data/lib/prawn/graphics/transparency.rb +20 -18
  29. data/lib/prawn/graphics.rb +153 -115
  30. data/lib/prawn/grid.rb +93 -50
  31. data/lib/prawn/image_handler.rb +4 -4
  32. data/lib/prawn/images/image.rb +3 -2
  33. data/lib/prawn/images/jpg.rb +31 -24
  34. data/lib/prawn/images/png.rb +101 -68
  35. data/lib/prawn/images.rb +64 -56
  36. data/lib/prawn/measurement_extensions.rb +10 -9
  37. data/lib/prawn/measurements.rb +20 -23
  38. data/lib/prawn/outline.rb +96 -75
  39. data/lib/prawn/repeater.rb +16 -16
  40. data/lib/prawn/security/arcfour.rb +2 -2
  41. data/lib/prawn/security.rb +100 -85
  42. data/lib/prawn/soft_mask.rb +37 -38
  43. data/lib/prawn/stamp.rb +28 -13
  44. data/lib/prawn/text/box.rb +24 -29
  45. data/lib/prawn/text/formatted/arranger.rb +108 -63
  46. data/lib/prawn/text/formatted/box.rb +187 -124
  47. data/lib/prawn/text/formatted/fragment.rb +24 -20
  48. data/lib/prawn/text/formatted/line_wrap.rb +133 -73
  49. data/lib/prawn/text/formatted/parser.rb +147 -127
  50. data/lib/prawn/text/formatted/wrap.rb +48 -35
  51. data/lib/prawn/text/formatted.rb +5 -5
  52. data/lib/prawn/text.rb +103 -68
  53. data/lib/prawn/transformation_stack.rb +44 -0
  54. data/lib/prawn/utilities.rb +10 -22
  55. data/lib/prawn/version.rb +5 -0
  56. data/lib/prawn/view.rb +101 -0
  57. data/lib/prawn.rb +39 -54
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +34 -25
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +8 -9
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +48 -0
  66. data/manual/bounding_box/bounding_box.rb +30 -28
  67. data/manual/bounding_box/bounds.rb +12 -13
  68. data/manual/bounding_box/canvas.rb +7 -8
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +25 -18
  72. data/manual/bounding_box/russian_boxes.rb +18 -18
  73. data/manual/bounding_box/stretchy.rb +12 -14
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -32
  76. data/manual/document_and_page_options/background.rb +15 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +24 -22
  78. data/manual/document_and_page_options/metadata.rb +20 -18
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -13
  81. data/manual/document_and_page_options/print_scaling.rb +18 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +5 -6
  88. data/manual/graphics/fill_rules.rb +12 -11
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +46 -40
  91. data/manual/graphics/helper.rb +19 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +8 -9
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -9
  97. data/manual/graphics/scale.rb +14 -13
  98. data/manual/graphics/soft_masks.rb +4 -6
  99. data/manual/graphics/stroke_cap.rb +7 -8
  100. data/manual/graphics/stroke_dash.rb +15 -16
  101. data/manual/graphics/stroke_join.rb +6 -7
  102. data/manual/graphics/translate.rb +10 -10
  103. data/manual/graphics/transparency.rb +7 -9
  104. data/manual/how_to_read_this_manual.rb +8 -9
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +10 -11
  108. data/manual/images/images.rb +28 -27
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +16 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +10 -11
  114. data/manual/layout/content.rb +9 -10
  115. data/manual/layout/layout.rb +17 -18
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +22 -21
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +27 -23
  124. data/manual/repeatable_content/repeater.rb +15 -16
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +8 -11
  127. data/manual/security/permissions.rb +20 -15
  128. data/manual/security/security.rb +18 -18
  129. data/manual/table.rb +16 -0
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -12
  132. data/manual/text/column_box.rb +9 -11
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +10 -8
  137. data/manual/text/formatted_callbacks.rb +33 -23
  138. data/manual/text/formatted_text.rb +36 -25
  139. data/manual/text/free_flowing_text.rb +22 -23
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +15 -10
  145. data/manual/text/positioned_text.rb +16 -17
  146. data/manual/text/registering_families.rb +27 -24
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +30 -19
  149. data/manual/text/rotation.rb +33 -24
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +56 -54
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +24 -17
  155. data/manual/text/utf8.rb +12 -13
  156. data/manual/text/win_ansi_charset.rb +28 -25
  157. data/prawn.gemspec +45 -50
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +44 -0
  167. data/spec/prawn/document_spec.rb +805 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +544 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +872 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +229 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +512 -0
  180. data/spec/prawn/repeater_spec.rb +166 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +173 -0
  183. data/spec/prawn/text/box_spec.rb +1110 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +150 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -25
  198. data.tar.gz.sig +0 -0
  199. metadata +113 -276
  200. metadata.gz.sig +0 -0
  201. data/data/encodings/win_ansi.txt +0 -29
  202. data/data/images/16bit.alpha +0 -0
  203. data/data/images/16bit.color +0 -0
  204. data/data/images/16bit.png +0 -0
  205. data/data/images/arrow.png +0 -0
  206. data/data/images/arrow2.png +0 -0
  207. data/data/images/dice.alpha +0 -0
  208. data/data/images/dice.color +0 -0
  209. data/data/images/dice.png +0 -0
  210. data/data/images/dice_interlaced.png +0 -0
  211. data/data/images/fractal.jpg +0 -0
  212. data/data/images/indexed_color.dat +0 -0
  213. data/data/images/indexed_color.png +0 -0
  214. data/data/images/letterhead.jpg +0 -0
  215. data/data/images/license.md +0 -8
  216. data/data/images/page_white_text.alpha +0 -0
  217. data/data/images/page_white_text.color +0 -0
  218. data/data/images/page_white_text.png +0 -0
  219. data/data/images/pigs.jpg +0 -0
  220. data/data/images/prawn.png +0 -0
  221. data/data/images/ruport.png +0 -0
  222. data/data/images/ruport_data.dat +0 -0
  223. data/data/images/ruport_transparent.png +0 -0
  224. data/data/images/ruport_type0.png +0 -0
  225. data/data/images/stef.jpg +0 -0
  226. data/data/images/tru256.bmp +0 -0
  227. data/data/images/web-links.dat +0 -1
  228. data/data/images/web-links.png +0 -0
  229. data/data/pdfs/complex_template.pdf +0 -0
  230. data/data/pdfs/contains_ttf_font.pdf +0 -0
  231. data/data/pdfs/encrypted.pdf +0 -0
  232. data/data/pdfs/form.pdf +1 -819
  233. data/data/pdfs/hexagon.pdf +0 -61
  234. data/data/pdfs/indirect_reference.pdf +0 -86
  235. data/data/pdfs/multipage_template.pdf +0 -127
  236. data/data/pdfs/nested_pages.pdf +0 -118
  237. data/data/pdfs/page_without_mediabox.pdf +0 -193
  238. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  239. data/data/pdfs/two_hexagons.pdf +0 -90
  240. data/data/pdfs/version_1_6.pdf +0 -61
  241. data/data/shift_jis_text.txt +0 -1
  242. data/lib/prawn/document/graphics_state.rb +0 -73
  243. data/lib/prawn/font/afm.rb +0 -247
  244. data/lib/prawn/table/cell/image.rb +0 -69
  245. data/lib/prawn/table/cell/in_table.rb +0 -33
  246. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  247. data/lib/prawn/table/cell/subtable.rb +0 -66
  248. data/lib/prawn/table/cell/text.rb +0 -154
  249. data/lib/prawn/table/cell.rb +0 -772
  250. data/lib/prawn/table/cells.rb +0 -255
  251. data/lib/prawn/table/column_width_calculator.rb +0 -182
  252. data/lib/prawn/table.rb +0 -644
  253. data/manual/table/basic_block.rb +0 -53
  254. data/manual/table/before_rendering_page.rb +0 -26
  255. data/manual/table/cell_border_lines.rb +0 -24
  256. data/manual/table/cell_borders_and_bg.rb +0 -31
  257. data/manual/table/cell_dimensions.rb +0 -30
  258. data/manual/table/cell_text.rb +0 -38
  259. data/manual/table/column_widths.rb +0 -30
  260. data/manual/table/content_and_subtables.rb +0 -39
  261. data/manual/table/creation.rb +0 -27
  262. data/manual/table/filtering.rb +0 -36
  263. data/manual/table/flow_and_header.rb +0 -17
  264. data/manual/table/image_cells.rb +0 -33
  265. data/manual/table/position.rb +0 -29
  266. data/manual/table/row_colors.rb +0 -20
  267. data/manual/table/span.rb +0 -30
  268. data/manual/table/style.rb +0 -22
  269. data/manual/table/table.rb +0 -52
  270. data/manual/table/width.rb +0 -27
  271. data/spec/acceptance/png.rb +0 -25
  272. data/spec/annotations_spec.rb +0 -74
  273. data/spec/bounding_box_spec.rb +0 -510
  274. data/spec/cell_spec.rb +0 -629
  275. data/spec/column_box_spec.rb +0 -65
  276. data/spec/destinations_spec.rb +0 -15
  277. data/spec/document_spec.rb +0 -730
  278. data/spec/extensions/mocha.rb +0 -46
  279. data/spec/font_metric_cache_spec.rb +0 -52
  280. data/spec/font_spec.rb +0 -449
  281. data/spec/formatted_text_arranger_spec.rb +0 -421
  282. data/spec/formatted_text_box_spec.rb +0 -639
  283. data/spec/formatted_text_fragment_spec.rb +0 -298
  284. data/spec/graphics_spec.rb +0 -669
  285. data/spec/grid_spec.rb +0 -96
  286. data/spec/image_handler_spec.rb +0 -54
  287. data/spec/images_spec.rb +0 -153
  288. data/spec/inline_formatted_text_parser_spec.rb +0 -564
  289. data/spec/jpg_spec.rb +0 -25
  290. data/spec/line_wrap_spec.rb +0 -344
  291. data/spec/measurement_units_spec.rb +0 -25
  292. data/spec/outline_spec.rb +0 -430
  293. data/spec/png_spec.rb +0 -237
  294. data/spec/reference_spec.rb +0 -25
  295. data/spec/repeater_spec.rb +0 -160
  296. data/spec/security_spec.rb +0 -158
  297. data/spec/soft_mask_spec.rb +0 -79
  298. data/spec/span_spec.rb +0 -44
  299. data/spec/stamp_spec.rb +0 -160
  300. data/spec/stroke_styles_spec.rb +0 -211
  301. data/spec/table/span_dummy_spec.rb +0 -17
  302. data/spec/table_spec.rb +0 -1527
  303. data/spec/text_at_spec.rb +0 -115
  304. data/spec/text_box_spec.rb +0 -1034
  305. data/spec/text_rendering_mode_spec.rb +0 -45
  306. data/spec/text_spacing_spec.rb +0 -93
  307. data/spec/text_spec.rb +0 -437
  308. data/spec/text_with_inline_formatting_spec.rb +0 -35
  309. data/spec/transparency_spec.rb +0 -91
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
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 which
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 font
86
+ # Raises "Bad font family" if no font family is defined for the current
87
+ # font
87
88
  #
88
- # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
89
+ # Raises <tt>Prawn::Errors::CannotFit</tt> if not wide enough to print
89
90
  # any text
90
91
  #
91
- def formatted_text_box(array, options={})
92
- Text::Formatted::Box.new(array, options.merge(:document => self)).render
92
+ def formatted_text_box(array, options = {})
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
@@ -136,38 +137,39 @@ module Prawn
136
137
 
137
138
  # See Prawn::Text#text_box for valid options
138
139
  #
139
- def initialize(formatted_text, options={})
140
- @inked = false
140
+ def initialize(formatted_text, options = {})
141
+ @inked = false
141
142
  Prawn.verify_options(valid_options, options)
142
- options = options.dup
143
+ options = options.dup
143
144
 
144
145
  self.class.extensions.reverse_each { |e| extend e }
145
146
 
146
- @overflow = options[:overflow] || :truncate
147
+ @overflow = options[:overflow] || :truncate
148
+ @disable_wrap_by_char = options[:disable_wrap_by_char]
147
149
 
148
150
  self.original_text = formatted_text
149
- @text = nil
150
-
151
- @document = options[:document]
152
- @direction = options[:direction] || @document.text_direction
153
- @fallback_fonts = options[:fallback_fonts] ||
154
- @document.fallback_fonts
155
- @at = (options[:at] ||
156
- [@document.bounds.left, @document.bounds.top]).dup
157
- @width = options[:width] ||
158
- @document.bounds.right - @at[0]
159
- @height = options[:height] || default_height
160
- @align = options[:align] ||
161
- (@direction == :rtl ? :right : :left)
162
- @vertical_align = options[:valign] || :top
163
- @leading = options[:leading] || @document.default_leading
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
164
167
  @character_spacing = options[:character_spacing] ||
165
- @document.character_spacing
166
- @mode = options[:mode] || @document.text_rendering_mode
167
- @rotate = options[:rotate] || 0
168
- @rotate_around = options[:rotate_around] || :upper_left
169
- @single_line = options[:single_line]
170
- @skip_encoding = options[:skip_encoding] || @document.skip_encoding
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,27 +185,30 @@ module Prawn
183
185
  @overflow = :truncate
184
186
  end
185
187
  @min_font_size = options[:min_font_size] || 5
186
- if options[:kerning].nil? then
188
+ if options[:kerning].nil?
187
189
  options[:kerning] = @document.default_kerning?
188
190
  end
189
- @options = { :kerning => options[:kerning],
190
- :size => options[:size],
191
- :style => options[:style] }
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 initialize.
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> accepts
199
- # a <tt>:dry_run => true</tt> option. If provided, then everything is
200
- # executed as if rendering, with the exception that nothing is drawn on
201
- # the page. Useful for look-ahead computations of height, unprinted text,
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
- def render(flags={})
211
+ def render(flags = {})
207
212
  unprinted_text = []
208
213
 
209
214
  @document.save_font do
@@ -211,28 +216,27 @@ module Prawn
211
216
  @document.text_rendering_mode(@mode) do
212
217
  process_options
213
218
 
214
- if @skip_encoding
215
- text = original_text
216
- else
217
- text = normalize_encoding
218
- end
219
+ text = normalized_text(flags)
219
220
 
220
221
  @document.font_size(@font_size) do
221
222
  shrink_to_fit(text) if @overflow == :shrink_to_fit
222
223
  process_vertical_alignment(text)
223
224
  @inked = true unless flags[:dry_run]
224
- if @rotate != 0 && @inked
225
- unprinted_text = render_rotated(text)
226
- else
227
- unprinted_text = wrap(text)
228
- end
225
+ unprinted_text =
226
+ if @rotate != 0 && @inked
227
+ render_rotated(text)
228
+ else
229
+ wrap(text)
230
+ end
229
231
  @inked = false
230
232
  end
231
233
  end
232
234
  end
233
235
  end
234
236
 
235
- unprinted_text
237
+ unprinted_text.map do |e|
238
+ e.merge(text: @document.font.to_utf8(e[:text]))
239
+ end
236
240
  end
237
241
 
238
242
  # The width available at this point in the box
@@ -245,13 +249,16 @@ module Prawn
245
249
  #
246
250
  def height
247
251
  return 0 if @baseline_y.nil? || @descender.nil?
252
+
248
253
  (@baseline_y - @descender).abs
249
254
  end
250
255
 
251
256
  # <tt>fragment</tt> is a Prawn::Text::Formatted::Fragment object
252
257
  #
253
- def draw_fragment(fragment, accumulated_width=0, line_width=0, word_spacing=0) #:nodoc:
254
- case(@align)
258
+ def draw_fragment(
259
+ fragment, accumulated_width = 0, line_width = 0, word_spacing = 0
260
+ ) #:nodoc:
261
+ case @align
255
262
  when :left
256
263
  x = @at[0]
257
264
  when :center
@@ -259,11 +266,15 @@ module Prawn
259
266
  when :right
260
267
  x = @at[0] + @width - line_width
261
268
  when :justify
262
- if @direction == :ltr
263
- x = @at[0]
264
- else
265
- x = @at[0] + @width - line_width
266
- end
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'
267
278
  end
268
279
 
269
280
  x += accumulated_width
@@ -278,15 +289,21 @@ module Prawn
278
289
  if @inked
279
290
  draw_fragment_underlays(fragment)
280
291
 
281
- @document.word_spacing(word_spacing) {
292
+ @document.word_spacing(word_spacing) do
282
293
  if @draw_text_callback
283
- @draw_text_callback.call(fragment.text, :at => [x, y],
284
- :kerning => @kerning)
294
+ @draw_text_callback.call(
295
+ fragment.text,
296
+ at: [x, y],
297
+ kerning: @kerning
298
+ )
285
299
  else
286
- @document.draw_text!(fragment.text, :at => [x, y],
287
- :kerning => @kerning)
300
+ @document.draw_text!(
301
+ fragment.text,
302
+ at: [x, y],
303
+ kerning: @kerning
304
+ )
288
305
  end
289
- }
306
+ end
290
307
 
291
308
  draw_fragment_overlays(fragment)
292
309
  end
@@ -327,27 +344,39 @@ module Prawn
327
344
 
328
345
  # @private
329
346
  def self.inherited(base)
347
+ super
330
348
  extensions.each { |e| base.extensions << e }
331
349
  end
332
350
 
333
351
  def valid_options
334
- PDF::Core::Text::VALID_OPTIONS + [:at, :height, :width,
335
- :align, :valign,
336
- :rotate, :rotate_around,
337
- :overflow, :min_font_size,
338
- :leading, :character_spacing,
339
- :mode, :single_line,
340
- :skip_encoding,
341
- :document,
342
- :direction,
343
- :fallback_fonts,
344
- :draw_text_callback]
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
365
+ ]
345
366
  end
346
367
 
347
368
  private
348
369
 
370
+ def normalized_text(flags)
371
+ text = normalize_encoding
372
+
373
+ text.each { |t| t.delete(:color) } if flags[:dry_run]
374
+
375
+ text
376
+ end
377
+
349
378
  def original_text
350
- @original_array.collect { |hash| hash.dup }
379
+ @original_array.map(&:dup)
351
380
  end
352
381
 
353
382
  def original_text=(formatted_text)
@@ -390,33 +419,41 @@ module Prawn
390
419
 
391
420
  original_font = @document.font.family
392
421
  fragment_font = hash[:font] || original_font
393
- @document.font(fragment_font)
394
422
 
395
423
  fallback_fonts = @fallback_fonts.dup
396
424
  # always default back to the current font if the glyph is missing from
397
425
  # all fonts
398
426
  fallback_fonts << fragment_font
399
427
 
400
- hash[:text].each_char do |char|
401
- @document.font(fragment_font)
402
- font_glyph_pairs << [find_font_for_this_glyph(char,
403
- @document.font.family,
404
- fallback_fonts.dup),
405
- char]
428
+ @document.save_font do
429
+ hash[:text].each_char do |char|
430
+ font_glyph_pairs << [
431
+ find_font_for_this_glyph(
432
+ char,
433
+ fragment_font,
434
+ fallback_fonts.dup
435
+ ),
436
+ char
437
+ ]
438
+ end
406
439
  end
407
440
 
408
- @document.font(original_font)
441
+ # Don't add a :font to fragments if it wasn't there originally
442
+ if hash[:font].nil?
443
+ font_glyph_pairs.each do |pair|
444
+ pair[0] = nil if pair[0] == original_font
445
+ end
446
+ end
409
447
 
410
448
  form_fragments_from_like_font_glyph_pairs(font_glyph_pairs, hash)
411
449
  end
412
450
 
413
451
  def find_font_for_this_glyph(char, current_font, fallback_fonts)
414
- if fallback_fonts.length == 0 || @document.font.glyph_present?(char)
452
+ @document.font(current_font)
453
+ if fallback_fonts.empty? || @document.font.glyph_present?(char)
415
454
  current_font
416
455
  else
417
- current_font = fallback_fonts.shift
418
- @document.font(current_font)
419
- find_font_for_this_glyph(char, @document.font.family, fallback_fonts)
456
+ find_font_for_this_glyph(char, fallback_fonts.shift, fallback_fonts)
420
457
  end
421
458
  end
422
459
 
@@ -426,11 +463,11 @@ module Prawn
426
463
  current_font = nil
427
464
 
428
465
  font_glyph_pairs.each do |font, char|
429
- if font != current_font
466
+ if font != current_font || fragments.count.zero?
430
467
  current_font = font
431
468
  fragment = hash.dup
432
469
  fragment[:text] = char
433
- fragment[:font] = font
470
+ fragment[:font] = font unless font.nil?
434
471
  fragments << fragment
435
472
  else
436
473
  fragment[:text] += char
@@ -441,8 +478,8 @@ module Prawn
441
478
  end
442
479
 
443
480
  def move_baseline_down
444
- if @baseline_y == 0
445
- @baseline_y = -@ascender
481
+ if @baseline_y.zero?
482
+ @baseline_y = -@ascender
446
483
  else
447
484
  @baseline_y -= (@line_height + @leading)
448
485
  end
@@ -466,29 +503,46 @@ module Prawn
466
503
  # we need to wait until render() is called so that the fonts are set
467
504
  # up properly for wrapping. So guard with a boolean to ensure this is
468
505
  # only run once.
469
- return if defined?(@vertical_alignment_processed) && @vertical_alignment_processed
506
+ if defined?(@vertical_alignment_processed) &&
507
+ @vertical_alignment_processed
508
+ return
509
+ end
510
+
470
511
  @vertical_alignment_processed = true
471
512
 
472
513
  return if @vertical_align == :top
514
+
473
515
  wrap(text)
474
516
 
475
517
  case @vertical_align
476
518
  when :center
477
- @at[1] = @at[1] - (@height - height) * 0.5
519
+ @at[1] -= (@height - height + @descender) * 0.5
478
520
  when :bottom
479
- @at[1] = @at[1] - (@height - height) + @descender
521
+ @at[1] -= (@height - height)
480
522
  end
523
+
481
524
  @height = height
482
525
  end
483
526
 
484
527
  # Decrease the font size until the text fits or the min font
485
528
  # size is reached
486
529
  def shrink_to_fit(text)
487
- wrap(text)
488
- until @everything_printed || @font_size <= @min_font_size
530
+ loop do
531
+ if @disable_wrap_by_char && @font_size > @min_font_size
532
+ begin
533
+ wrap(text)
534
+ rescue Errors::CannotFit
535
+ # Ignore errors while we can still attempt smaller
536
+ # font sizes.
537
+ end
538
+ else
539
+ wrap(text)
540
+ end
541
+
542
+ break if @everything_printed || @font_size <= @min_font_size
543
+
489
544
  @font_size = [@font_size - 0.5, @min_font_size].max
490
545
  @document.font_size = @font_size
491
- wrap(text)
492
546
  end
493
547
  end
494
548
 
@@ -497,7 +551,7 @@ module Prawn
497
551
  # document.process_text_options sets the font
498
552
  @document.process_text_options(@options)
499
553
  @font_size = @options[:size]
500
- @kerning = @options[:kerning]
554
+ @kerning = @options[:kerning]
501
555
  end
502
556
 
503
557
  def render_rotated(text)
@@ -521,7 +575,7 @@ module Prawn
521
575
  y = @at[1]
522
576
  end
523
577
 
524
- @document.rotate(@rotate, :origin => [x, y]) do
578
+ @document.rotate(@rotate, origin: [x, y]) do
525
579
  unprinted_text = wrap(text)
526
580
  end
527
581
  unprinted_text
@@ -545,47 +599,56 @@ module Prawn
545
599
 
546
600
  def draw_fragment_overlay_link(fragment)
547
601
  return unless fragment.link
602
+
548
603
  box = fragment.absolute_bounding_box
549
- @document.link_annotation(box,
550
- :Border => [0, 0, 0],
551
- :A => { :Type => :Action,
552
- :S => :URI,
553
- :URI => PDF::Core::LiteralString.new(fragment.link) })
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
+ )
554
613
  end
555
614
 
556
615
  def draw_fragment_overlay_anchor(fragment)
557
616
  return unless fragment.anchor
617
+
558
618
  box = fragment.absolute_bounding_box
559
- @document.link_annotation(box,
560
- :Border => [0, 0, 0],
561
- :Dest => fragment.anchor)
619
+ @document.link_annotation(
620
+ box,
621
+ Border: [0, 0, 0],
622
+ Dest: fragment.anchor
623
+ )
562
624
  end
563
625
 
564
626
  def draw_fragment_overlay_local(fragment)
565
627
  return unless fragment.local
628
+
566
629
  box = fragment.absolute_bounding_box
567
- @document.link_annotation(box,
568
- :Border => [0, 0, 0],
569
- :A => { :Type => :Action,
570
- :S => :Launch,
571
- :F => PDF::Core::LiteralString.new(fragment.local),
572
- :NewWindow => true })
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
+ )
573
640
  end
574
641
 
575
642
  def draw_fragment_overlay_styles(fragment)
576
- underline = fragment.styles.include?(:underline)
577
- if underline
643
+ if fragment.styles.include?(:underline)
578
644
  @document.stroke_line(fragment.underline_points)
579
645
  end
580
646
 
581
- strikethrough = fragment.styles.include?(:strikethrough)
582
- if strikethrough
647
+ if fragment.styles.include?(:strikethrough)
583
648
  @document.stroke_line(fragment.strikethrough_points)
584
649
  end
585
650
  end
586
-
587
651
  end
588
-
589
652
  end
590
653
  end
591
654
  end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # text/formatted/fragment.rb : Implements information about a formatted fragment
4
4
  #
@@ -9,14 +9,11 @@
9
9
  module Prawn
10
10
  module Text
11
11
  module Formatted
12
-
13
-
14
12
  # Prawn::Text::Formatted::Fragment is a state store for a formatted text
15
13
  # fragment. It does not render anything.
16
14
  #
17
15
  # @private
18
16
  class Fragment
19
-
20
17
  attr_reader :format_state, :text
21
18
  attr_writer :width
22
19
  attr_accessor :line_height, :descender, :ascender
@@ -27,14 +24,14 @@ module Prawn
27
24
  @document = document
28
25
  @word_spacing = 0
29
26
 
30
- # keep the original value of "text", so we can reinitialize @text if formatting parameters
31
- # like text direction are changed
27
+ # keep the original value of "text", so we can reinitialize @text if
28
+ # formatting parameters like text direction are changed
32
29
  @original_text = text
33
30
  @text = process_text(@original_text)
34
31
  end
35
32
 
36
33
  def width
37
- if @word_spacing == 0 then @width
34
+ if @word_spacing.zero? then @width
38
35
  else @width + @word_spacing * space_count
39
36
  end
40
37
  end
@@ -131,7 +128,7 @@ module Prawn
131
128
  end
132
129
 
133
130
  def space_count
134
- @text.count(" ")
131
+ @text.count(' ')
135
132
  end
136
133
 
137
134
  def callback_objects
@@ -209,11 +206,18 @@ module Prawn
209
206
 
210
207
  def process_text(text)
211
208
  string = strip_zero_width_spaces(text)
209
+
212
210
  if exclude_trailing_white_space?
213
- string = process_soft_hyphens(string.rstrip)
211
+ string = string.rstrip
212
+
213
+ if soft_hyphens_need_processing?(string)
214
+ string = process_soft_hyphens(string[0..-2]) + string[-1..-1]
215
+ end
216
+ elsif soft_hyphens_need_processing?(string)
217
+ string = process_soft_hyphens(string)
214
218
  end
215
- case direction
216
- when :rtl
219
+
220
+ if direction == :rtl
217
221
  string.reverse
218
222
  else
219
223
  string
@@ -224,29 +228,29 @@ module Prawn
224
228
  @format_state[:exclude_trailing_white_space]
225
229
  end
226
230
 
231
+ def soft_hyphens_need_processing?(string)
232
+ !string.empty? && normalized_soft_hyphen
233
+ end
234
+
227
235
  def normalized_soft_hyphen
228
236
  @format_state[:normalized_soft_hyphen]
229
237
  end
230
238
 
231
239
  def process_soft_hyphens(string)
232
- if string.length > 0 && normalized_soft_hyphen
233
- if string.encoding != normalized_soft_hyphen.encoding
234
- string.force_encoding(normalized_soft_hyphen.encoding)
235
- end
236
- string[0..-2].gsub(normalized_soft_hyphen, "") + string[-1..-1]
237
- else
238
- string
240
+ if string.encoding != normalized_soft_hyphen.encoding
241
+ string.force_encoding(normalized_soft_hyphen.encoding)
239
242
  end
243
+
244
+ string.gsub(normalized_soft_hyphen, '')
240
245
  end
241
246
 
242
247
  def strip_zero_width_spaces(string)
243
248
  if string.encoding == ::Encoding::UTF_8
244
- string.gsub(Prawn::Text::ZWSP, "")
249
+ string.gsub(Prawn::Text::ZWSP, '')
245
250
  else
246
251
  string
247
252
  end
248
253
  end
249
-
250
254
  end
251
255
  end
252
256
  end