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
data/lib/prawn/text.rb CHANGED
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # text.rb : Implements PDF text primitives
4
4
  #
@@ -6,24 +6,24 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
- require "zlib"
9
+ require 'zlib'
10
10
 
11
- require_relative "../pdf/core/text"
12
- require_relative "text/formatted"
13
- require_relative "text/box"
11
+ require_relative 'text/formatted'
12
+ require_relative 'text/box'
14
13
 
15
14
  module Prawn
16
15
  module Text
17
-
18
16
  include PDF::Core::Text
19
17
  include Prawn::Text::Formatted
20
18
 
21
19
  # No-Break Space
22
- Prawn::Text::NBSP = " "
20
+ NBSP = "\u00A0"
23
21
  # Zero Width Space (indicate word boundaries without a space)
24
- Prawn::Text::ZWSP = [8203].pack("U")
22
+ ZWSP = "\u200B"
25
23
  # Soft Hyphen (invisible, except when causing a line break)
26
- Prawn::Text::SHY = "­"
24
+ SHY = "\u00AD"
25
+
26
+ # @group Stable API
27
27
 
28
28
  # If you want text to flow onto a new page or between columns, this is the
29
29
  # method to use. If, instead, if you want to place bounded text outside of
@@ -97,11 +97,6 @@ module Prawn
97
97
  # <tt>\<link></link></tt>::
98
98
  # with the following attributes
99
99
  # <tt>href="http://example.com"</tt>:: an external link
100
- # <tt>anchor="ToC"</tt>::
101
- # where the value of the anchor attribute is the name of a
102
- # destination that has already been or will be registered
103
- # using PDF::Core::Destinations#add_dest. A clickable link
104
- # will be created to that destination.
105
100
  # Note that you must explicitly underline and color using the
106
101
  # appropriate tags if you which to draw attention to the link
107
102
  #
@@ -118,7 +113,7 @@ module Prawn
118
113
  # the current font familly. [current style]
119
114
  # <tt>:indent_paragraphs</tt>:: <tt>number</tt>. The amount to indent the
120
115
  # first line of each paragraph. Omit this
121
- # option if you do not want indenting
116
+ # option if you do not want indenting.
122
117
  # <tt>:direction</tt>::
123
118
  # <tt>:ltr</tt>, <tt>:rtl</tt>, Direction of the text (left-to-right
124
119
  # or right-to-left) [value of document.text_direction]
@@ -142,9 +137,9 @@ module Prawn
142
137
  # each line is included below the last line;
143
138
  # otherwise, document.y is placed just below the
144
139
  # descender of the last line printed [true]
145
- # <tt>:mode</tt>:: The text rendering mode to use. Use this to specify if the
146
- # text should render with the fill color, stroke color or
147
- # both. See the comments to text_rendering_mode() to see
140
+ # <tt>:mode</tt>:: The text rendering mode to use. Use this to specify if
141
+ # the text should render with the fill color, stroke color
142
+ # or both. See the comments to text_rendering_mode() to see
148
143
  # a list of valid options. [0]
149
144
  #
150
145
  # == Exceptions
@@ -154,23 +149,24 @@ module Prawn
154
149
  # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
155
150
  # any text
156
151
  #
157
- def text(string, options={})
152
+ def text(string, options = {})
158
153
  return false if string.nil?
154
+
159
155
  # we modify the options. don't change the user's hash
160
156
  options = options.dup
161
157
 
162
- if p = options[:inline_format]
158
+ p = options[:inline_format]
159
+ if p
163
160
  p = [] unless p.is_a?(Array)
164
161
  options.delete(:inline_format)
165
- array = self.text_formatter.format(string, *p)
162
+ array = text_formatter.format(string, *p)
166
163
  else
167
- array = [{ :text => string }]
164
+ array = [{ text: string }]
168
165
  end
169
166
 
170
167
  formatted_text(array, options)
171
168
  end
172
169
 
173
-
174
170
  # Draws formatted text to the page.
175
171
  # Formatted text is comprised of an array of hashes, where each hash defines
176
172
  # text and format information. See Text::Formatted#formatted_text_box for
@@ -191,37 +187,33 @@ module Prawn
191
187
  #
192
188
  # Same as for #text
193
189
  #
194
- def formatted_text(array, options={})
190
+ def formatted_text(array, options = {})
195
191
  options = inspect_options_for_text(options.dup)
196
192
 
197
- if color = options.delete(:color)
198
- array = array.map do |fragment|
199
- fragment[:color] ? fragment : fragment.merge(:color => color)
200
- end
193
+ color = options.delete(:color)
194
+ if color
195
+ array =
196
+ array.map do |fragment|
197
+ fragment[:color] ? fragment : fragment.merge(color: color)
198
+ end
201
199
  end
202
200
 
203
201
  if @indent_paragraphs
204
- self.text_formatter.array_paragraphs(array).each do |paragraph|
205
- options[:skip_encoding] = false
202
+ text_formatter.array_paragraphs(array).each do |paragraph|
206
203
  remaining_text = draw_indented_formatted_line(paragraph, options)
207
- options[:skip_encoding] = true
208
-
209
- if @no_text_printed
210
- # unless this paragraph was an empty line
211
- unless @all_text_printed
212
- @bounding_box.move_past_bottom
213
- options[:skip_encoding] = false
214
- remaining_text = draw_indented_formatted_line(paragraph, options)
215
- options[:skip_encoding] = true
216
- end
204
+
205
+ if @no_text_printed && !@all_text_printed
206
+ @bounding_box.move_past_bottom
207
+ remaining_text = draw_indented_formatted_line(paragraph, options)
217
208
  end
218
209
 
219
- remaining_text = fill_formatted_text_box(remaining_text, options)
220
- draw_remaining_formatted_text_on_new_pages(remaining_text, options)
210
+ unless @all_text_printed
211
+ remaining_text = fill_formatted_text_box(remaining_text, options)
212
+ draw_remaining_formatted_text_on_new_pages(remaining_text, options)
213
+ end
221
214
  end
222
215
  else
223
216
  remaining_text = fill_formatted_text_box(array, options)
224
- options[:skip_encoding] = true
225
217
  draw_remaining_formatted_text_on_new_pages(remaining_text, options)
226
218
  end
227
219
  end
@@ -245,7 +237,8 @@ module Prawn
245
237
  # == Rotation
246
238
  #
247
239
  # Text can be rotated before it is placed on the canvas by specifying the
248
- # <tt>:rotate</tt> option with a given angle. Rotation occurs counter-clockwise.
240
+ # <tt>:rotate</tt> option with a given angle. Rotation occurs
241
+ # counter-clockwise.
249
242
  #
250
243
  # == Encoding
251
244
  #
@@ -262,7 +255,8 @@ module Prawn
262
255
  #
263
256
  # == Options (default values marked in [])
264
257
  #
265
- # <tt>:at</tt>:: <tt>[x, y]</tt>(required). The position at which to start the text
258
+ # <tt>:at</tt>:: <tt>[x, y]</tt>(required). The position at which to start
259
+ # the text
266
260
  # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
267
261
  # is available with the current font)
268
262
  # [value of default_kerning?]
@@ -286,11 +280,29 @@ module Prawn
286
280
  text = text.to_s.dup
287
281
  save_font do
288
282
  process_text_options(options)
289
- font.normalize_encoding!(text)
283
+ text = font.normalize_encoding(text)
290
284
  font_size(options[:size]) { draw_text!(text, options) }
291
285
  end
292
286
  end
293
287
 
288
+ # Low level text placement method. All font and size alterations
289
+ # should already be set
290
+ #
291
+ def draw_text!(text, options)
292
+ unless font.unicode? || font.class.hide_m17n_warning || text.ascii_only?
293
+ warn "PDF's built-in fonts have very limited support for " \
294
+ "internationalized text.\nIf you need full UTF-8 support, " \
295
+ "consider using an external font instead.\n\nTo disable this " \
296
+ "warning, add the following line to your code:\n" \
297
+ "Prawn::Fonts::AFM.hide_m17n_warning = true\n"
298
+
299
+ font.class.hide_m17n_warning = true
300
+ end
301
+
302
+ x, y = map_to_absolute(options[:at])
303
+ add_text_content(text, x, y, options)
304
+ end
305
+
294
306
  # Gets height of text in PDF points.
295
307
  # Same options as #text, except as noted.
296
308
  # Not compatible with :indent_paragraphs option
@@ -307,8 +319,8 @@ module Prawn
307
319
  # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
308
320
  # any text
309
321
  #
310
- def height_of(string, options={})
311
- height_of_formatted([{ :text => string }], options)
322
+ def height_of(string, options = {})
323
+ height_of_formatted([{ text: string }], options)
312
324
  end
313
325
 
314
326
  # Gets height of formatted text in PDF points.
@@ -321,16 +333,17 @@ module Prawn
321
333
  # :size => 24,
322
334
  # :styles => [:bold, :italic] }])
323
335
  #
324
- def height_of_formatted(array, options={})
336
+ def height_of_formatted(array, options = {})
325
337
  if options[:indent_paragraphs]
326
- raise NotImplementedError, ":indent_paragraphs option not available" +
327
- "with height_of"
338
+ raise NotImplementedError,
339
+ ':indent_paragraphs option not available with height_of'
328
340
  end
329
341
  process_final_gap_option(options)
330
- box = Text::Formatted::Box.new(array,
331
- options.merge(:height => 100000000,
332
- :document => self))
333
- box.render(:dry_run => true)
342
+ box = Text::Formatted::Box.new(
343
+ array,
344
+ options.merge(height: 100_000_000, document: self)
345
+ )
346
+ box.render(dry_run: true)
334
347
 
335
348
  height = box.height
336
349
  height += box.line_gap + box.leading if @final_gap
@@ -340,7 +353,7 @@ module Prawn
340
353
  private
341
354
 
342
355
  def draw_remaining_formatted_text_on_new_pages(remaining_text, options)
343
- while remaining_text.length > 0
356
+ until remaining_text.empty?
344
357
  @bounding_box.move_past_bottom
345
358
  previous_remaining_text = remaining_text
346
359
  remaining_text = fill_formatted_text_box(remaining_text, options)
@@ -349,8 +362,15 @@ module Prawn
349
362
  end
350
363
 
351
364
  def draw_indented_formatted_line(string, options)
352
- indent(@indent_paragraphs) do
353
- fill_formatted_text_box(string, options.dup.merge(:single_line => true))
365
+ gap =
366
+ if options.fetch(:direction, text_direction) == :ltr
367
+ [@indent_paragraphs, 0]
368
+ else
369
+ [0, @indent_paragraphs]
370
+ end
371
+
372
+ indent(*gap) do
373
+ fill_formatted_text_box(string, options.dup.merge(single_line: true))
354
374
  end
355
375
  end
356
376
 
@@ -368,33 +388,41 @@ module Prawn
368
388
  end
369
389
 
370
390
  def merge_text_box_positioning_options(options)
371
- bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
372
- @bounding_box.absolute_bottom
391
+ bottom =
392
+ if @bounding_box.stretchy?
393
+ @margin_box.absolute_bottom
394
+ else
395
+ @bounding_box.absolute_bottom
396
+ end
373
397
 
374
398
  options[:height] = y - bottom
375
399
  options[:width] = bounds.width
376
- options[:at] = [@bounding_box.left_side - @bounding_box.absolute_left,
377
- y - @bounding_box.absolute_bottom]
400
+ options[:at] = [
401
+ @bounding_box.left_side - @bounding_box.absolute_left,
402
+ y - @bounding_box.absolute_bottom
403
+ ]
378
404
  end
379
405
 
380
406
  def inspect_options_for_draw_text(options)
381
407
  if options[:at].nil?
382
- raise ArgumentError, "The :at option is required for draw_text"
408
+ raise ArgumentError, 'The :at option is required for draw_text'
383
409
  elsif options[:align]
384
- raise ArgumentError, "The :align option does not work with draw_text"
410
+ raise ArgumentError, 'The :align option does not work with draw_text'
385
411
  end
386
- if options[:kerning].nil? then
412
+
413
+ if options[:kerning].nil?
387
414
  options[:kerning] = default_kerning?
388
415
  end
389
- valid_options = PDF::Core::Text::VALID_OPTIONS + [:at, :rotate]
416
+ valid_options = PDF::Core::Text::VALID_OPTIONS + %i[at rotate]
390
417
  Prawn.verify_options(valid_options, options)
391
418
  options
392
419
  end
393
420
 
394
421
  def inspect_options_for_text(options)
395
422
  if options[:at]
396
- raise ArgumentError, ":at is no longer a valid option with text." +
397
- "use draw_text or text_box instead"
423
+ raise ArgumentError,
424
+ ':at is no longer a valid option with text.' \
425
+ 'use draw_text or text_box instead'
398
426
  end
399
427
  process_final_gap_option(options)
400
428
  process_indent_paragraphs_option(options)
@@ -412,13 +440,17 @@ module Prawn
412
440
  options.delete(:indent_paragraphs)
413
441
  end
414
442
 
415
- def move_text_position(dy)
416
- bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
417
- @bounding_box.absolute_bottom
443
+ def move_text_position(amount)
444
+ bottom =
445
+ if @bounding_box.stretchy?
446
+ @margin_box.absolute_bottom
447
+ else
448
+ @bounding_box.absolute_bottom
449
+ end
418
450
 
419
- @bounding_box.move_past_bottom if (y - dy) < bottom
451
+ @bounding_box.move_past_bottom if (y - amount) < bottom
420
452
 
421
- self.y -= dy
453
+ self.y -= amount
422
454
  end
423
455
  end
424
456
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # transformation_stack.rb : Stores the transformations that have been applied to
4
+ # the document
5
+ #
6
+ # Copyright 2015, Roger Nesbitt. All Rights Reserved.
7
+ #
8
+ # This is free software. Please see the LICENSE and COPYING files for details.
9
+
10
+ require 'matrix'
11
+
12
+ # rubocop: disable Metrics/ParameterLists, Naming/MethodParameterName
13
+ module Prawn
14
+ module TransformationStack
15
+ def add_to_transformation_stack(a, b, c, d, e, f)
16
+ @transformation_stack ||= [[]]
17
+ @transformation_stack.last.push([a, b, c, d, e, f].map(&:to_f))
18
+ end
19
+
20
+ def save_transformation_stack
21
+ @transformation_stack ||= [[]]
22
+ @transformation_stack.push(@transformation_stack.last.dup)
23
+ end
24
+
25
+ def restore_transformation_stack
26
+ @transformation_stack&.pop
27
+ end
28
+
29
+ def current_transformation_matrix_with_translation(x = 0, y = 0)
30
+ transformations = (@transformation_stack || [[]]).last
31
+
32
+ matrix = Matrix.identity(3)
33
+
34
+ transformations.each do |a, b, c, d, e, f|
35
+ matrix *= Matrix[[a, c, e], [b, d, f], [0, 0, 1]]
36
+ end
37
+
38
+ matrix *= Matrix[[1, 0, x], [0, 1, y], [0, 0, 1]]
39
+
40
+ matrix.to_a[0..1].transpose.flatten
41
+ end
42
+ end
43
+ end
44
+ # rubocop: enable Metrics/ParameterLists, Naming/MethodParameterName
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # utilities.rb : General-purpose utility classes which don't fit anywhere else
4
4
  #
@@ -6,39 +6,29 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
- require 'thread'
10
-
11
9
  module Prawn
12
-
13
- # Throughout the Prawn codebase, repeated calculations which can benefit from caching are made
14
- # In some cases, caching and reusing results can not only save CPU cycles but also greatly
15
- # reduce memory requirements
10
+ # Throughout the Prawn codebase, repeated calculations which can benefit from
11
+ # caching are made.
12
+ # In some cases, caching and reusing results can not only save CPU cycles but
13
+ # also greatly reduce memory requirements
16
14
  # But at the same time, we don't want to throw away thread safety
17
15
  # We have two interchangeable thread-safe cache implementations:
18
16
 
17
+ # @private
19
18
  class SynchronizedCache
20
- # As an optimization, this could access the hash directly on VMs with a global interpreter lock (like MRI)
19
+ # As an optimization, this could access the hash directly on VMs with
20
+ # a global interpreter lock (like MRI)
21
21
  def initialize
22
22
  @cache = {}
23
23
  @mutex = Mutex.new
24
24
  end
25
+
25
26
  def [](key)
26
27
  @mutex.synchronize { @cache[key] }
27
28
  end
28
- def []=(key,value)
29
- @mutex.synchronize { @cache[key] = value }
30
- end
31
- end
32
29
 
33
- class ThreadLocalCache
34
- def initialize
35
- @cache_id = "cache_#{self.object_id}".to_sym
36
- end
37
- def [](key)
38
- (Thread.current[@cache_id] ||= {})[key]
39
- end
40
- def []=(key,value)
41
- (Thread.current[@cache_id] ||= {})[key] = value
30
+ def []=(key, value)
31
+ @mutex.synchronize { @cache[key] = value }
42
32
  end
43
33
  end
44
34
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prawn
4
+ VERSION = '2.4.0'
5
+ end
data/lib/prawn/view.rb ADDED
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # prawn/view.rb : Implements a mixin for Prawn's DSL
4
+ #
5
+ # This is free software. Please see the LICENSE and COPYING files for details.
6
+
7
+ module Prawn
8
+ # This mixin allows you to create modular Prawn code without the
9
+ # need to create subclasses of Prawn::Document.
10
+ #
11
+ # class Greeter
12
+ # include Prawn::View
13
+ #
14
+ # # Optional override: allows you to set document options or even use
15
+ # # a custom document class
16
+ # def document
17
+ # @document ||= Prawn::Document.new(page_size: 'A4')
18
+ # end
19
+ #
20
+ # def initialize(name)
21
+ # @name = name
22
+ # end
23
+ #
24
+ # def say_hello
25
+ # text "Hello, #{@name}!"
26
+ # end
27
+ #
28
+ # def say_goodbye
29
+ # font("Courier") do
30
+ # text "Goodbye, #{@name}!"
31
+ # end
32
+ # end
33
+ # end
34
+ #
35
+ # greeter = Greeter.new("Gregory")
36
+ #
37
+ # greeter.say_hello
38
+ # greeter.say_goodbye
39
+ #
40
+ # greeter.save_as("greetings.pdf")
41
+ #
42
+ # The short story about why you should use this mixin rather than
43
+ # creating subclasses of +Prawn::Document+ is that it helps
44
+ # prevent accidental conflicts between your code and Prawn's
45
+ # code.
46
+ #
47
+ # Here's the slightly longer story...
48
+ #
49
+ # By using composition rather than inheritance under the hood, this
50
+ # mixin allows you to keep your state separate from +Prawn::Document+'s
51
+ # state, and also will prevent unexpected method name collisions due
52
+ # to late binding effects.
53
+ #
54
+ # This mixin is mostly meant for extending Prawn's functionality
55
+ # with your own additions, but you can also use it to replace or
56
+ # wrap existing Prawn methods. Calling +super+ will still work
57
+ # as expected, and alternatively you can explictly call
58
+ # +document.some_method+ to delegate to Prawn where needed.
59
+ module View
60
+ # @group Experimental API
61
+
62
+ # Lazily instantiates a +Prawn::Document+ object.
63
+ #
64
+ # You can also redefine this method in your own classes to use
65
+ # a custom document class.
66
+ def document
67
+ @document ||= Prawn::Document.new
68
+ end
69
+
70
+ # Delegates all unhandled calls to object returned by +document+ method.
71
+ # (which is an instance of Prawn::Document by default)
72
+ def method_missing(method_name, *arguments, &block)
73
+ return super unless document.respond_to?(method_name)
74
+
75
+ document.public_send(method_name, *arguments, &block)
76
+ end
77
+
78
+ def respond_to_missing?(method_name, _include_all = false)
79
+ document.respond_to?(method_name) || super
80
+ end
81
+
82
+ # Syntactic sugar that uses +instance_eval+ under the hood to provide
83
+ # a block-based DSL.
84
+ #
85
+ # greeter.update do
86
+ # say_hello
87
+ # say_goodbye
88
+ # end
89
+ #
90
+ def update(&block)
91
+ instance_eval(&block)
92
+ end
93
+
94
+ # Syntatic sugar that calls +document.render_file+ under the hood.
95
+ #
96
+ # greeter.save_as("greetings.pdf")
97
+ def save_as(filename)
98
+ document.render_file(filename)
99
+ end
100
+ end
101
+ end