prawn 0.13.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 (348) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +10 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -16
  6. data/Rakefile +17 -39
  7. data/lib/prawn/document/bounding_box.rb +85 -42
  8. data/lib/prawn/document/column_box.rb +21 -11
  9. data/lib/prawn/document/internals.rb +40 -147
  10. data/lib/prawn/document/span.rb +25 -17
  11. data/lib/prawn/document.rb +286 -245
  12. data/lib/prawn/encoding.rb +68 -101
  13. data/lib/prawn/errors.rb +47 -43
  14. data/lib/prawn/font.rb +204 -155
  15. data/lib/prawn/font_metric_cache.rb +25 -21
  16. data/lib/prawn/fonts/afm.rb +292 -0
  17. data/lib/prawn/{font → fonts}/dfont.rb +7 -13
  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 +142 -80
  21. data/lib/prawn/graphics/blend_mode.rb +65 -0
  22. data/lib/prawn/graphics/cap_style.rb +6 -5
  23. data/lib/prawn/graphics/color.rb +47 -44
  24. data/lib/prawn/graphics/dash.rb +30 -13
  25. data/lib/prawn/graphics/join_style.rb +13 -6
  26. data/lib/prawn/graphics/patterns.rb +221 -90
  27. data/lib/prawn/graphics/transformation.rb +21 -12
  28. data/lib/prawn/graphics/transparency.rb +21 -17
  29. data/lib/prawn/graphics.rb +155 -128
  30. data/lib/prawn/{layout/grid.rb → grid.rb} +110 -47
  31. data/lib/prawn/image_handler.rb +16 -2
  32. data/lib/prawn/images/image.rb +4 -2
  33. data/lib/prawn/images/jpg.rb +39 -30
  34. data/lib/prawn/images/png.rb +132 -169
  35. data/lib/prawn/images.rb +70 -62
  36. data/lib/prawn/measurement_extensions.rb +15 -10
  37. data/lib/prawn/measurements.rb +22 -23
  38. data/lib/prawn/outline.rb +301 -13
  39. data/lib/prawn/repeater.rb +19 -17
  40. data/lib/prawn/security/arcfour.rb +54 -0
  41. data/lib/prawn/security.rb +108 -86
  42. data/lib/prawn/soft_mask.rb +40 -41
  43. data/lib/prawn/stamp.rb +29 -12
  44. data/lib/prawn/text/box.rb +27 -29
  45. data/lib/prawn/text/formatted/arranger.rb +110 -67
  46. data/lib/prawn/text/formatted/box.rb +233 -165
  47. data/lib/prawn/text/formatted/fragment.rb +27 -27
  48. data/lib/prawn/text/formatted/line_wrap.rb +137 -97
  49. data/lib/prawn/text/formatted/parser.rb +149 -127
  50. data/lib/prawn/text/formatted/wrap.rb +57 -37
  51. data/lib/prawn/text/formatted.rb +6 -4
  52. data/lib/prawn/text.rb +105 -73
  53. data/lib/prawn/transformation_stack.rb +44 -0
  54. data/lib/prawn/utilities.rb +11 -21
  55. data/lib/prawn/version.rb +5 -0
  56. data/lib/prawn/view.rb +101 -0
  57. data/lib/prawn.rb +42 -68
  58. data/{data/images/fractal.jpg → manual/absolute_position.pdf} +0 -0
  59. data/manual/basic_concepts/adding_pages.rb +9 -10
  60. data/manual/basic_concepts/basic_concepts.rb +33 -24
  61. data/manual/basic_concepts/creation.rb +10 -11
  62. data/manual/basic_concepts/cursor.rb +9 -10
  63. data/manual/basic_concepts/measurement.rb +10 -11
  64. data/manual/basic_concepts/origin.rb +8 -9
  65. data/manual/basic_concepts/other_cursor_helpers.rb +17 -18
  66. data/manual/basic_concepts/view.rb +48 -0
  67. data/manual/bounding_box/bounding_box.rb +31 -29
  68. data/manual/bounding_box/bounds.rb +17 -18
  69. data/manual/bounding_box/canvas.rb +8 -9
  70. data/manual/bounding_box/creation.rb +8 -9
  71. data/manual/bounding_box/indentation.rb +22 -23
  72. data/manual/bounding_box/nesting.rb +32 -25
  73. data/manual/bounding_box/russian_boxes.rb +19 -19
  74. data/manual/bounding_box/stretchy.rb +18 -20
  75. data/manual/contents.rb +35 -0
  76. data/manual/cover.rb +43 -0
  77. data/manual/document_and_page_options/background.rb +16 -14
  78. data/manual/document_and_page_options/document_and_page_options.rb +26 -23
  79. data/manual/document_and_page_options/metadata.rb +21 -19
  80. data/manual/document_and_page_options/page_margins.rb +20 -22
  81. data/manual/document_and_page_options/page_size.rb +15 -15
  82. data/manual/document_and_page_options/print_scaling.rb +23 -0
  83. data/manual/example_helper.rb +5 -408
  84. data/manual/graphics/blend_mode.rb +52 -0
  85. data/manual/graphics/circle_and_ellipse.rb +8 -9
  86. data/manual/graphics/color.rb +11 -13
  87. data/manual/graphics/common_lines.rb +13 -12
  88. data/manual/graphics/fill_and_stroke.rb +10 -11
  89. data/manual/graphics/fill_rules.rb +13 -12
  90. data/manual/graphics/gradients.rb +28 -22
  91. data/manual/graphics/graphics.rb +52 -46
  92. data/manual/graphics/helper.rb +20 -10
  93. data/manual/graphics/line_width.rb +13 -12
  94. data/manual/graphics/lines_and_curves.rb +13 -14
  95. data/manual/graphics/polygon.rb +10 -12
  96. data/manual/graphics/rectangle.rb +7 -8
  97. data/manual/graphics/rotate.rb +9 -12
  98. data/manual/graphics/scale.rb +19 -18
  99. data/manual/graphics/soft_masks.rb +5 -7
  100. data/manual/graphics/stroke_cap.rb +10 -11
  101. data/manual/graphics/stroke_dash.rb +16 -17
  102. data/manual/graphics/stroke_join.rb +10 -11
  103. data/manual/graphics/translate.rb +13 -13
  104. data/manual/graphics/transparency.rb +11 -13
  105. data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +23 -25
  106. data/manual/images/absolute_position.rb +9 -10
  107. data/manual/images/fit.rb +9 -10
  108. data/manual/images/horizontal.rb +13 -14
  109. data/manual/images/images.rb +31 -30
  110. data/manual/images/plain_image.rb +6 -7
  111. data/manual/images/scale.rb +12 -13
  112. data/manual/images/vertical.rb +19 -17
  113. data/manual/images/width_and_height.rb +13 -14
  114. data/manual/layout/boxes.rb +14 -15
  115. data/manual/layout/content.rb +12 -13
  116. data/manual/layout/layout.rb +19 -20
  117. data/manual/layout/simple_grid.rb +8 -9
  118. data/manual/outline/add_subsection_to.rb +26 -27
  119. data/manual/outline/insert_section_after.rb +19 -20
  120. data/manual/outline/outline.rb +23 -22
  121. data/manual/outline/sections_and_pages.rb +24 -25
  122. data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
  123. data/manual/repeatable_content/page_numbering.rb +20 -19
  124. data/manual/repeatable_content/repeatable_content.rb +26 -22
  125. data/manual/repeatable_content/repeater.rb +18 -19
  126. data/manual/repeatable_content/stamp.rb +18 -19
  127. data/manual/security/encryption.rb +8 -11
  128. data/manual/security/permissions.rb +20 -15
  129. data/manual/security/security.rb +20 -20
  130. data/manual/table.rb +16 -0
  131. data/manual/text/alignment.rb +17 -18
  132. data/manual/text/color.rb +13 -13
  133. data/manual/text/column_box.rb +10 -12
  134. data/manual/text/fallback_fonts.rb +29 -25
  135. data/manual/text/font.rb +17 -18
  136. data/manual/text/font_size.rb +21 -22
  137. data/manual/text/font_style.rb +12 -10
  138. data/manual/text/formatted_callbacks.rb +36 -26
  139. data/manual/text/formatted_text.rb +41 -34
  140. data/manual/text/free_flowing_text.rb +28 -29
  141. data/manual/text/inline.rb +23 -26
  142. data/manual/text/kerning_and_character_spacing.rb +20 -21
  143. data/manual/text/leading.rb +10 -11
  144. data/manual/text/line_wrapping.rb +40 -21
  145. data/manual/text/paragraph_indentation.rb +17 -12
  146. data/manual/text/positioned_text.rb +19 -20
  147. data/manual/text/registering_families.rb +33 -30
  148. data/manual/text/rendering_and_color.rb +11 -12
  149. data/manual/text/right_to_left_text.rb +31 -20
  150. data/manual/text/rotation.rb +36 -27
  151. data/manual/text/single_usage.rb +13 -14
  152. data/manual/text/text.rb +62 -62
  153. data/manual/text/text_box_excess.rb +22 -19
  154. data/manual/text/text_box_extensions.rb +21 -18
  155. data/manual/text/text_box_overflow.rb +28 -21
  156. data/manual/text/utf8.rb +16 -17
  157. data/manual/text/win_ansi_charset.rb +29 -26
  158. data/prawn.gemspec +45 -43
  159. data/spec/extensions/encoding_helpers.rb +4 -3
  160. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  161. data/spec/prawn/document/column_box_spec.rb +75 -0
  162. data/spec/prawn/document/security_spec.rb +176 -0
  163. data/spec/prawn/document_annotations_spec.rb +76 -0
  164. data/spec/prawn/document_destinations_spec.rb +15 -0
  165. data/spec/prawn/document_grid_spec.rb +99 -0
  166. data/spec/prawn/document_reference_spec.rb +27 -0
  167. data/spec/prawn/document_span_spec.rb +44 -0
  168. data/spec/prawn/document_spec.rb +805 -0
  169. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  170. data/spec/prawn/font_spec.rb +544 -0
  171. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  172. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  173. data/spec/prawn/graphics_spec.rb +872 -0
  174. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  175. data/spec/prawn/image_handler_spec.rb +53 -0
  176. data/spec/prawn/images/jpg_spec.rb +20 -0
  177. data/spec/prawn/images/png_spec.rb +283 -0
  178. data/spec/prawn/images_spec.rb +229 -0
  179. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  180. data/spec/prawn/outline_spec.rb +512 -0
  181. data/spec/prawn/repeater_spec.rb +166 -0
  182. data/spec/prawn/soft_mask_spec.rb +74 -0
  183. data/spec/prawn/stamp_spec.rb +173 -0
  184. data/spec/prawn/text/box_spec.rb +1110 -0
  185. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  186. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  187. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  188. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  189. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  190. data/spec/prawn/text_draw_text_spec.rb +150 -0
  191. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  192. data/spec/prawn/text_spacing_spec.rb +95 -0
  193. data/spec/prawn/text_spec.rb +603 -0
  194. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  195. data/spec/prawn/transformation_stack_spec.rb +66 -0
  196. data/spec/prawn/view_spec.rb +63 -0
  197. data/spec/prawn_manual_spec.rb +35 -0
  198. data/spec/spec_helper.rb +22 -21
  199. data.tar.gz.sig +0 -0
  200. metadata +168 -307
  201. metadata.gz.sig +0 -0
  202. data/README.md +0 -109
  203. data/data/encodings/win_ansi.txt +0 -29
  204. data/data/images/16bit.alpha +0 -0
  205. data/data/images/16bit.dat +0 -0
  206. data/data/images/16bit.png +0 -0
  207. data/data/images/arrow.png +0 -0
  208. data/data/images/arrow2.png +0 -0
  209. data/data/images/barcode_issue.png +0 -0
  210. data/data/images/dice.alpha +0 -0
  211. data/data/images/dice.dat +0 -0
  212. data/data/images/dice.png +0 -0
  213. data/data/images/dice_interlaced.png +0 -0
  214. data/data/images/indexed_color.dat +0 -0
  215. data/data/images/indexed_color.png +0 -0
  216. data/data/images/letterhead.jpg +0 -0
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.dat +0 -0
  219. data/data/images/page_white_text.png +0 -0
  220. data/data/images/pigs.jpg +0 -0
  221. data/data/images/prawn.png +0 -0
  222. data/data/images/ruport.png +0 -0
  223. data/data/images/ruport_data.dat +0 -0
  224. data/data/images/ruport_transparent.png +0 -0
  225. data/data/images/ruport_type0.png +0 -0
  226. data/data/images/stef.jpg +0 -0
  227. data/data/images/tru256.bmp +0 -0
  228. data/data/images/web-links.dat +0 -1
  229. data/data/images/web-links.png +0 -0
  230. data/data/pdfs/complex_template.pdf +0 -0
  231. data/data/pdfs/contains_ttf_font.pdf +0 -0
  232. data/data/pdfs/encrypted.pdf +0 -0
  233. data/data/pdfs/form.pdf +1 -819
  234. data/data/pdfs/hexagon.pdf +0 -61
  235. data/data/pdfs/indirect_reference.pdf +0 -86
  236. data/data/pdfs/multipage_template.pdf +0 -127
  237. data/data/pdfs/nested_pages.pdf +0 -118
  238. data/data/pdfs/page_without_mediabox.pdf +0 -193
  239. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  240. data/data/pdfs/two_hexagons.pdf +0 -90
  241. data/data/pdfs/version_1_6.pdf +0 -61
  242. data/data/shift_jis_text.txt +0 -1
  243. data/lib/pdf/core/annotations.rb +0 -60
  244. data/lib/pdf/core/byte_string.rb +0 -9
  245. data/lib/pdf/core/destinations.rb +0 -90
  246. data/lib/pdf/core/document_state.rb +0 -78
  247. data/lib/pdf/core/filter_list.rb +0 -51
  248. data/lib/pdf/core/filters.rb +0 -36
  249. data/lib/pdf/core/graphics_state.rb +0 -68
  250. data/lib/pdf/core/literal_string.rb +0 -16
  251. data/lib/pdf/core/name_tree.rb +0 -177
  252. data/lib/pdf/core/object_store.rb +0 -320
  253. data/lib/pdf/core/outline.rb +0 -315
  254. data/lib/pdf/core/page.rb +0 -212
  255. data/lib/pdf/core/page_geometry.rb +0 -126
  256. data/lib/pdf/core/pdf_object.rb +0 -124
  257. data/lib/pdf/core/reference.rb +0 -103
  258. data/lib/pdf/core/stream.rb +0 -98
  259. data/lib/pdf/core/text.rb +0 -275
  260. data/lib/pdf/core.rb +0 -35
  261. data/lib/prawn/compatibility.rb +0 -91
  262. data/lib/prawn/document/graphics_state.rb +0 -73
  263. data/lib/prawn/document/snapshot.rb +0 -89
  264. data/lib/prawn/font/afm.rb +0 -203
  265. data/lib/prawn/layout.rb +0 -20
  266. data/lib/prawn/table/cell/image.rb +0 -70
  267. data/lib/prawn/table/cell/in_table.rb +0 -27
  268. data/lib/prawn/table/cell/span_dummy.rb +0 -92
  269. data/lib/prawn/table/cell/subtable.rb +0 -65
  270. data/lib/prawn/table/cell/text.rb +0 -153
  271. data/lib/prawn/table/cell.rb +0 -770
  272. data/lib/prawn/table/cells.rb +0 -295
  273. data/lib/prawn/table.rb +0 -643
  274. data/manual/example_file.rb +0 -116
  275. data/manual/example_package.rb +0 -53
  276. data/manual/example_section.rb +0 -46
  277. data/manual/manual/cover.rb +0 -35
  278. data/manual/manual/foreword.rb +0 -85
  279. data/manual/manual/manual.rb +0 -35
  280. data/manual/syntax_highlight.rb +0 -52
  281. data/manual/table/basic_block.rb +0 -53
  282. data/manual/table/before_rendering_page.rb +0 -26
  283. data/manual/table/cell_border_lines.rb +0 -24
  284. data/manual/table/cell_borders_and_bg.rb +0 -31
  285. data/manual/table/cell_dimensions.rb +0 -30
  286. data/manual/table/cell_text.rb +0 -38
  287. data/manual/table/column_widths.rb +0 -30
  288. data/manual/table/content_and_subtables.rb +0 -39
  289. data/manual/table/creation.rb +0 -27
  290. data/manual/table/filtering.rb +0 -36
  291. data/manual/table/flow_and_header.rb +0 -17
  292. data/manual/table/image_cells.rb +0 -33
  293. data/manual/table/position.rb +0 -29
  294. data/manual/table/row_colors.rb +0 -20
  295. data/manual/table/span.rb +0 -30
  296. data/manual/table/style.rb +0 -22
  297. data/manual/table/table.rb +0 -52
  298. data/manual/table/width.rb +0 -27
  299. data/manual/templates/full_template.rb +0 -25
  300. data/manual/templates/page_template.rb +0 -48
  301. data/manual/templates/templates.rb +0 -27
  302. data/manual/text/group.rb +0 -29
  303. data/spec/acceptance/png.rb +0 -23
  304. data/spec/annotations_spec.rb +0 -74
  305. data/spec/bounding_box_spec.rb +0 -493
  306. data/spec/cell_spec.rb +0 -628
  307. data/spec/column_box_spec.rb +0 -33
  308. data/spec/destinations_spec.rb +0 -15
  309. data/spec/document_spec.rb +0 -761
  310. data/spec/extensions/mocha.rb +0 -44
  311. data/spec/filters_spec.rb +0 -34
  312. data/spec/font_metric_cache_spec.rb +0 -52
  313. data/spec/font_spec.rb +0 -464
  314. data/spec/formatted_text_arranger_spec.rb +0 -421
  315. data/spec/formatted_text_box_spec.rb +0 -650
  316. data/spec/formatted_text_fragment_spec.rb +0 -298
  317. data/spec/graphics_spec.rb +0 -651
  318. data/spec/grid_spec.rb +0 -85
  319. data/spec/image_handler_spec.rb +0 -42
  320. data/spec/images_spec.rb +0 -157
  321. data/spec/inline_formatted_text_parser_spec.rb +0 -564
  322. data/spec/jpg_spec.rb +0 -25
  323. data/spec/line_wrap_spec.rb +0 -333
  324. data/spec/measurement_units_spec.rb +0 -23
  325. data/spec/name_tree_spec.rb +0 -112
  326. data/spec/object_store_spec.rb +0 -170
  327. data/spec/outline_spec.rb +0 -448
  328. data/spec/pdf_object_spec.rb +0 -172
  329. data/spec/png_spec.rb +0 -240
  330. data/spec/reference_spec.rb +0 -82
  331. data/spec/repeater_spec.rb +0 -158
  332. data/spec/security_spec.rb +0 -158
  333. data/spec/snapshot_spec.rb +0 -186
  334. data/spec/soft_mask_spec.rb +0 -117
  335. data/spec/span_spec.rb +0 -44
  336. data/spec/stamp_spec.rb +0 -158
  337. data/spec/stream_spec.rb +0 -58
  338. data/spec/stroke_styles_spec.rb +0 -211
  339. data/spec/table/span_dummy_spec.rb +0 -17
  340. data/spec/table_spec.rb +0 -1355
  341. data/spec/template_spec.rb +0 -351
  342. data/spec/text_at_spec.rb +0 -130
  343. data/spec/text_box_spec.rb +0 -1030
  344. data/spec/text_rendering_mode_spec.rb +0 -45
  345. data/spec/text_spacing_spec.rb +0 -93
  346. data/spec/text_spec.rb +0 -425
  347. data/spec/text_with_inline_formatting_spec.rb +0 -35
  348. data/spec/transparency_spec.rb +0 -89
@@ -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,12 +9,11 @@
9
9
  module Prawn
10
10
  module Text
11
11
  module Formatted
12
-
13
12
  # Prawn::Text::Formatted::Fragment is a state store for a formatted text
14
13
  # fragment. It does not render anything.
15
14
  #
15
+ # @private
16
16
  class Fragment
17
-
18
17
  attr_reader :format_state, :text
19
18
  attr_writer :width
20
19
  attr_accessor :line_height, :descender, :ascender
@@ -25,14 +24,14 @@ module Prawn
25
24
  @document = document
26
25
  @word_spacing = 0
27
26
 
28
- # keep the original value of "text", so we can reinitialize @text if formatting parameters
29
- # 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
30
29
  @original_text = text
31
30
  @text = process_text(@original_text)
32
31
  end
33
32
 
34
33
  def width
35
- if @word_spacing == 0 then @width
34
+ if @word_spacing.zero? then @width
36
35
  else @width + @word_spacing * space_count
37
36
  end
38
37
  end
@@ -129,7 +128,7 @@ module Prawn
129
128
  end
130
129
 
131
130
  def space_count
132
- @text.count(" ")
131
+ @text.count(' ')
133
132
  end
134
133
 
135
134
  def callback_objects
@@ -207,16 +206,19 @@ module Prawn
207
206
 
208
207
  def process_text(text)
209
208
  string = strip_zero_width_spaces(text)
209
+
210
210
  if exclude_trailing_white_space?
211
- string = process_soft_hyphens(string.rstrip)
212
- end
213
- case direction
214
- when :rtl
215
- if ruby_18 { true }
216
- string.scan(/./mu).reverse.join
217
- else
218
- string.reverse
211
+ string = string.rstrip
212
+
213
+ if soft_hyphens_need_processing?(string)
214
+ string = process_soft_hyphens(string[0..-2]) + string[-1..-1]
219
215
  end
216
+ elsif soft_hyphens_need_processing?(string)
217
+ string = process_soft_hyphens(string)
218
+ end
219
+
220
+ if direction == :rtl
221
+ string.reverse
220
222
  else
221
223
  string
222
224
  end
@@ -226,31 +228,29 @@ module Prawn
226
228
  @format_state[:exclude_trailing_white_space]
227
229
  end
228
230
 
231
+ def soft_hyphens_need_processing?(string)
232
+ !string.empty? && normalized_soft_hyphen
233
+ end
234
+
229
235
  def normalized_soft_hyphen
230
236
  @format_state[:normalized_soft_hyphen]
231
237
  end
232
238
 
233
239
  def process_soft_hyphens(string)
234
- if string.length > 0 && normalized_soft_hyphen
235
- ruby_19 {
236
- if string.encoding != normalized_soft_hyphen.encoding
237
- string.force_encoding(normalized_soft_hyphen.encoding)
238
- end
239
- }
240
- string[0..-2].gsub(normalized_soft_hyphen, "") + string[-1..-1]
241
- else
242
- string
240
+ if string.encoding != normalized_soft_hyphen.encoding
241
+ string.force_encoding(normalized_soft_hyphen.encoding)
243
242
  end
243
+
244
+ string.gsub(normalized_soft_hyphen, '')
244
245
  end
245
246
 
246
247
  def strip_zero_width_spaces(string)
247
- if !"".respond_to?(:encoding) || string.encoding.to_s == "UTF-8"
248
- string.gsub(Prawn::Text::ZWSP, "")
248
+ if string.encoding == ::Encoding::UTF_8
249
+ string.gsub(Prawn::Text::ZWSP, '')
249
250
  else
250
251
  string
251
252
  end
252
253
  end
253
-
254
254
  end
255
255
  end
256
256
  end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # core/text/formatted/line_wrap.rb : Implements individual line wrapping of
4
4
  # formatted text
@@ -11,9 +11,8 @@
11
11
  module Prawn
12
12
  module Text
13
13
  module Formatted #:nodoc:
14
-
14
+ # @private
15
15
  class LineWrap #:nodoc:
16
-
17
16
  # The width of the last wrapped line
18
17
  #
19
18
  def width
@@ -25,7 +24,11 @@ module Prawn
25
24
 
26
25
  # Whether this line is the last line in the paragraph
27
26
  def paragraph_finished?
28
- @newline_encountered || is_next_string_newline? || @arranger.finished?
27
+ @newline_encountered || next_string_newline? || @arranger.finished?
28
+ end
29
+
30
+ def tokenize(fragment)
31
+ fragment.scan(scan_pattern(fragment.encoding))
29
32
  end
30
33
 
31
34
  # Work in conjunction with the PDF::Formatted::Arranger
@@ -35,8 +38,10 @@ module Prawn
35
38
  def wrap_line(options)
36
39
  initialize_line(options)
37
40
 
41
+ # rubocop: disable Lint/AssignmentInCondition
38
42
  while fragment = @arranger.next_string
39
- @fragment_output = ""
43
+ # rubocop: enable Lint/AssignmentInCondition
44
+ @fragment_output = +''
40
45
 
41
46
  fragment.lstrip! if first_fragment_on_this_line?(fragment)
42
47
  next if empty_line?(fragment)
@@ -58,47 +63,56 @@ module Prawn
58
63
  end
59
64
 
60
65
  def empty_line?(fragment)
61
- empty = line_empty? && fragment.empty? && is_next_string_newline?
62
- @arranger.update_last_string("", "", soft_hyphen) if empty
66
+ empty = line_empty? && fragment.empty? && next_string_newline?
67
+ if empty
68
+ @arranger.update_last_string('', '', soft_hyphen(fragment.encoding))
69
+ end
63
70
  empty
64
71
  end
65
72
 
66
- def is_next_string_newline?
73
+ def next_string_newline?
67
74
  @arranger.preview_next_string == "\n"
68
75
  end
69
76
 
70
77
  def apply_font_settings_and_add_fragment_to_line(fragment)
71
78
  result = nil
72
79
  @arranger.apply_font_settings do
73
- # if font has changed from Unicode to non-Unicode, or vice versa, the characters used for soft hyphens
74
- # and zero-width spaces will be different
75
- set_soft_hyphen_and_zero_width_space
76
80
  result = add_fragment_to_line(fragment)
77
81
  end
78
82
  result
79
83
  end
80
84
 
81
- # returns true iff all text was printed without running into the end of
85
+ # returns true if all text was printed without running into the end of
82
86
  # the line
83
87
  #
84
88
  def add_fragment_to_line(fragment)
85
- if fragment == ""
89
+ case fragment
90
+ when ''
86
91
  true
87
- elsif fragment == "\n"
92
+ when "\n"
88
93
  @newline_encountered = true
89
94
  false
90
95
  else
91
- fragment.scan(scan_pattern).each do |segment|
92
- if segment == zero_width_space
93
- segment_width = 0
94
- else
95
- segment_width = @document.width_of(segment, :kerning => @kerning)
96
- end
96
+ tokenize(fragment).each do |segment|
97
+ segment_width =
98
+ if segment == zero_width_space(segment.encoding)
99
+ 0
100
+ else
101
+ @document.width_of(segment, kerning: @kerning)
102
+ end
97
103
 
98
104
  if @accumulated_width + segment_width <= @width
99
105
  @accumulated_width += segment_width
106
+ shy = soft_hyphen(segment.encoding)
107
+ if segment[-1] == shy
108
+ sh_width = @document.width_of(shy, kerning: @kerning)
109
+ @accumulated_width -= sh_width
110
+ end
100
111
  @fragment_output += segment
101
112
  else
113
+ if @accumulated_width.zero? && @line_contains_more_than_one_word
114
+ @line_contains_more_than_one_word = false
115
+ end
102
116
  end_of_the_line_reached(segment)
103
117
  fragment_finished(fragment)
104
118
  return false
@@ -112,46 +126,83 @@ module Prawn
112
126
 
113
127
  # The pattern used to determine chunks of text to place on a given line
114
128
  #
115
- def scan_pattern
116
- pattern = "[^#{break_chars}]+#{soft_hyphen}|" +
117
- "[^#{break_chars}]+#{hyphen}+|" +
118
- "[^#{break_chars}]+|" +
119
- "[#{whitespace}]+|" +
120
- "#{hyphen}+[^#{break_chars}]*|" +
121
- "#{soft_hyphen}"
122
- new_regexp(pattern)
129
+ def scan_pattern(encoding = ::Encoding::UTF_8)
130
+ ebc = break_chars(encoding)
131
+ eshy = soft_hyphen(encoding)
132
+ ehy = hyphen(encoding)
133
+ ews = whitespace(encoding)
134
+
135
+ patterns = [
136
+ "[^#{ebc}]+#{eshy}",
137
+ "[^#{ebc}]+#{ehy}+",
138
+ "[^#{ebc}]+",
139
+ "[#{ews}]+",
140
+ "#{ehy}+[^#{ebc}]*",
141
+ eshy.to_s
142
+ ]
143
+
144
+ pattern = patterns
145
+ .map { |p| p.encode(encoding) }
146
+ .join('|')
147
+
148
+ Regexp.new(pattern)
123
149
  end
124
150
 
125
151
  # The pattern used to determine whether any word breaks exist on a
126
152
  # current line, which in turn determines whether character level
127
153
  # word breaking is needed
128
154
  #
129
- def word_division_scan_pattern
130
- new_regexp("\\s|[#{zero_width_space}#{soft_hyphen}#{hyphen}]")
155
+ def word_division_scan_pattern(encoding = ::Encoding::UTF_8)
156
+ common_whitespaces =
157
+ ["\t", "\n", "\v", "\r", ' '].map do |c|
158
+ c.encode(encoding)
159
+ end
160
+
161
+ Regexp.union(
162
+ common_whitespaces +
163
+ [
164
+ zero_width_space(encoding),
165
+ soft_hyphen(encoding),
166
+ hyphen(encoding)
167
+ ].compact
168
+ )
131
169
  end
132
170
 
133
- def break_chars
134
- "#{whitespace}#{soft_hyphen}#{hyphen}"
171
+ def soft_hyphen(encoding = ::Encoding::UTF_8)
172
+ Prawn::Text::SHY.encode(encoding)
173
+ rescue ::Encoding::InvalidByteSequenceError,
174
+ ::Encoding::UndefinedConversionError
175
+ nil
135
176
  end
136
177
 
137
- def whitespace
138
- " \\t#{zero_width_space}"
178
+ def break_chars(encoding = ::Encoding::UTF_8)
179
+ [
180
+ whitespace(encoding),
181
+ soft_hyphen(encoding),
182
+ hyphen(encoding)
183
+ ].join('')
139
184
  end
140
185
 
141
- def hyphen
142
- "-"
186
+ def zero_width_space(encoding = ::Encoding::UTF_8)
187
+ Prawn::Text::ZWSP.encode(encoding)
188
+ rescue ::Encoding::InvalidByteSequenceError,
189
+ ::Encoding::UndefinedConversionError
190
+ nil
143
191
  end
144
192
 
145
- def soft_hyphen
146
- @soft_hyphen
193
+ def whitespace(encoding = ::Encoding::UTF_8)
194
+ "\s\t#{zero_width_space(encoding)}".encode(encoding)
147
195
  end
148
196
 
149
- def zero_width_space
150
- @zero_width_space
197
+ def hyphen(_encoding = ::Encoding::UTF_8)
198
+ '-'
199
+ rescue ::Encoding::InvalidByteSequenceError,
200
+ ::Encoding::UndefinedConversionError
201
+ nil
151
202
  end
152
203
 
153
204
  def line_empty?
154
- @line_empty && @accumulated_width == 0
205
+ @line_empty && @accumulated_width.zero?
155
206
  end
156
207
 
157
208
  def initialize_line(options)
@@ -159,6 +210,8 @@ module Prawn
159
210
  @kerning = options[:kerning]
160
211
  @width = options[:width]
161
212
 
213
+ @disable_wrap_by_char = options[:disable_wrap_by_char]
214
+
162
215
  @accumulated_width = 0
163
216
  @line_empty = true
164
217
  @line_contains_more_than_one_word = false
@@ -170,52 +223,57 @@ module Prawn
170
223
  @line_full = false
171
224
  end
172
225
 
173
- def set_soft_hyphen_and_zero_width_space
174
- # this is done once per fragment, after the font settings for the fragment are applied --
175
- # it could actually be skipped if the font hasn't changed
176
- font = @document.font
177
- @soft_hyphen = font.normalize_encoding(Prawn::Text::SHY)
178
- @zero_width_space = font.unicode? ? Prawn::Text::ZWSP : ""
179
- end
180
-
181
226
  def fragment_finished(fragment)
182
227
  if fragment == "\n"
183
228
  @newline_encountered = true
184
229
  @line_empty = false
185
230
  else
186
- update_output_based_on_last_fragment(fragment, soft_hyphen)
231
+ update_output_based_on_last_fragment(
232
+ fragment,
233
+ soft_hyphen(fragment.encoding)
234
+ )
187
235
  update_line_status_based_on_last_output
188
- determine_whether_to_pull_preceding_fragment_to_join_this_one(fragment)
236
+ pull_preceding_fragment_to_join_this_one?(fragment)
189
237
  end
190
238
  remember_this_fragment_for_backward_looking_ops
191
239
  end
192
240
 
193
- def update_output_based_on_last_fragment(fragment, normalized_soft_hyphen=nil)
194
- remaining_text = fragment.slice(@fragment_output.length..fragment.length)
195
- raise Prawn::Errors::CannotFit if line_finished? && line_empty? &&
196
- @fragment_output.empty? && !fragment.strip.empty?
197
- @arranger.update_last_string(@fragment_output, remaining_text, normalized_soft_hyphen)
241
+ def update_output_based_on_last_fragment(
242
+ fragment, normalized_soft_hyphen = nil
243
+ )
244
+ remaining_text =
245
+ fragment.slice(@fragment_output.length..fragment.length)
246
+ if line_finished? && line_empty? && @fragment_output.empty? &&
247
+ !fragment.strip.empty?
248
+ raise Prawn::Errors::CannotFit
249
+ end
250
+
251
+ @arranger.update_last_string(
252
+ @fragment_output,
253
+ remaining_text,
254
+ normalized_soft_hyphen
255
+ )
198
256
  end
199
257
 
200
- def determine_whether_to_pull_preceding_fragment_to_join_this_one(current_fragment)
201
- if @fragment_output.empty? &&
202
- !current_fragment.empty? &&
203
- @line_contains_more_than_one_word
204
- unless previous_fragment_ended_with_breakable? ||
205
- fragment_begins_with_breakable?(current_fragment)
206
- @fragment_output = @previous_fragment_output_without_last_word
207
- update_output_based_on_last_fragment(@previous_fragment)
208
- end
258
+ def pull_preceding_fragment_to_join_this_one?(current_fragment)
259
+ if @fragment_output.empty? && !current_fragment.empty? &&
260
+ @line_contains_more_than_one_word &&
261
+ !(previous_fragment_ended_with_breakable? ||
262
+ fragment_begins_with_breakable?(current_fragment))
263
+ @fragment_output = @previous_fragment_output_without_last_word
264
+ update_output_based_on_last_fragment(@previous_fragment)
209
265
  end
210
266
  end
211
267
 
212
268
  def remember_this_fragment_for_backward_looking_ops
213
269
  @previous_fragment = @fragment_output.dup
214
270
  pf = @previous_fragment
215
- @previous_fragment_ended_with_breakable = pf =~ /[#{break_chars}]$/
216
- last_word = pf.slice(/[^#{break_chars}]*$/)
271
+ @previous_fragment_ended_with_breakable =
272
+ pf =~ /[#{break_chars(pf.encoding)}]$/
273
+ last_word = pf.slice(/[^#{break_chars(pf.encoding)}]*$/)
217
274
  last_word_length = last_word.nil? ? 0 : last_word.length
218
- @previous_fragment_output_without_last_word = pf.slice(0, pf.length - last_word_length)
275
+ @previous_fragment_output_without_last_word =
276
+ pf.slice(0, pf.length - last_word_length)
219
277
  end
220
278
 
221
279
  def previous_fragment_ended_with_breakable?
@@ -223,7 +281,7 @@ module Prawn
223
281
  end
224
282
 
225
283
  def fragment_begins_with_breakable?(fragment)
226
- fragment =~ /^[#{break_chars}]/
284
+ fragment =~ /^[#{break_chars(fragment.encoding)}]/
227
285
  end
228
286
 
229
287
  def line_finished?
@@ -231,34 +289,28 @@ module Prawn
231
289
  end
232
290
 
233
291
  def update_line_status_based_on_last_output
234
- @line_contains_more_than_one_word = true if @fragment_output =~ word_division_scan_pattern
292
+ if @fragment_output&.match?(word_division_scan_pattern(@fragment_output.encoding))
293
+ @line_contains_more_than_one_word = true
294
+ end
235
295
  end
236
296
 
237
297
  def end_of_the_line_reached(segment)
238
298
  update_line_status_based_on_last_output
239
- wrap_by_char(segment) unless @line_contains_more_than_one_word
299
+ unless @disable_wrap_by_char || @line_contains_more_than_one_word
300
+ wrap_by_char(segment)
301
+ end
240
302
  @line_full = true
241
303
  end
242
304
 
243
305
  def wrap_by_char(segment)
244
- # this conditional is only necessary for Ruby 1.8 compatibility
245
- # String#unicode_characters is a helper which iterates over UTF-8 characters
246
- # under Ruby 1.9, it is implemented simply by aliasing #each_char
247
- font = @document.font
248
- if font.unicode?
249
- segment.unicode_characters do |char|
250
- break unless append_char(char,font)
251
- end
252
- else
253
- segment.each_char do |char|
254
- break unless append_char(char,font)
255
- end
306
+ segment.each_char do |char|
307
+ break unless append_char(char)
256
308
  end
257
309
  end
258
310
 
259
- def append_char(char,font)
311
+ def append_char(char)
260
312
  # kerning doesn't make sense in the context of a single character
261
- char_width = font.compute_width_of(char)
313
+ char_width = @document.width_of(char)
262
314
 
263
315
  if @accumulated_width + char_width <= @width
264
316
  @accumulated_width += char_width
@@ -268,18 +320,6 @@ module Prawn
268
320
  false
269
321
  end
270
322
  end
271
-
272
- def new_regexp(pattern)
273
- regexp = ruby_19 {
274
- Regexp.new(pattern)
275
- }
276
- regexp = regexp || ruby_18 {
277
- lang = @document.font.unicode? ? 'U' : 'N'
278
- Regexp.new(pattern, 0, lang)
279
- }
280
- regexp
281
- end
282
-
283
323
  end
284
324
  end
285
325
  end