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
  # document.rb : Implements PDF document generation for Prawn
4
4
  #
@@ -6,23 +6,21 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
- require "stringio"
10
- require "prawn/document/bounding_box"
11
- require "prawn/document/column_box"
12
- require "prawn/document/internals"
13
- require "prawn/document/span"
14
- require "prawn/document/snapshot"
15
- require "prawn/document/graphics_state"
9
+ require 'stringio'
16
10
 
17
- module Prawn
11
+ require_relative 'document/bounding_box'
12
+ require_relative 'document/column_box'
13
+ require_relative 'document/internals'
14
+ require_relative 'document/span'
18
15
 
16
+ module Prawn
19
17
  # The Prawn::Document class is how you start creating a PDF document.
20
18
  #
21
19
  # There are three basic ways you can instantiate PDF Documents in Prawn, they
22
- # are through assignment, implicit block or explicit block. Below is an exmple
23
- # of each type, each example does exactly the same thing, makes a PDF document
24
- # with all the defaults and puts in the default font "Hello There" and then
25
- # saves it to the current directory as "example.pdf"
20
+ # are through assignment, implicit block or explicit block. Below is an
21
+ # example of each type, each example does exactly the same thing, makes a PDF
22
+ # document with all the defaults and puts in the default font "Hello There"
23
+ # and then saves it to the current directory as "example.pdf"
26
24
  #
27
25
  # For example, assignment can be like this:
28
26
  #
@@ -44,8 +42,8 @@ module Prawn
44
42
  # pdf.text words
45
43
  # end
46
44
  #
47
- # Usually, the block forms are used when you are simply creating a PDF document
48
- # that you want to immediately save or render out.
45
+ # Usually, the block forms are used when you are simply creating a PDF
46
+ # document that you want to immediately save or render out.
49
47
  #
50
48
  # See the new and generate methods for further details on the above.
51
49
  #
@@ -53,14 +51,25 @@ module Prawn
53
51
  include Prawn::Document::Internals
54
52
  include PDF::Core::Annotations
55
53
  include PDF::Core::Destinations
56
- include Prawn::Document::Snapshot
57
- include Prawn::Document::GraphicsState
58
54
  include Prawn::Document::Security
59
55
  include Prawn::Text
60
56
  include Prawn::Graphics
61
57
  include Prawn::Images
62
58
  include Prawn::Stamp
63
59
  include Prawn::SoftMask
60
+ include Prawn::TransformationStack
61
+
62
+ # @group Extension API
63
+
64
+ # NOTE: We probably need to rethink the options validation system, but this
65
+ # constant temporarily allows for extensions to modify the list.
66
+
67
+ VALID_OPTIONS = %i[
68
+ page_size page_layout margin left_margin
69
+ right_margin top_margin bottom_margin skip_page_creation
70
+ compress background info
71
+ text_formatter print_scaling
72
+ ].freeze
64
73
 
65
74
  # Any module added to this array will be included into instances of
66
75
  # Prawn::Document at the per-object level. These will also be inherited by
@@ -82,14 +91,29 @@ module Prawn
82
91
  # party!
83
92
  # end
84
93
  #
94
+ #
85
95
  def self.extensions
86
96
  @extensions ||= []
87
97
  end
88
98
 
89
- def self.inherited(base) #:nodoc:
99
+ # @private
100
+ def self.inherited(base)
101
+ super
90
102
  extensions.each { |e| base.extensions << e }
91
103
  end
92
104
 
105
+ # @group Stable Attributes
106
+
107
+ attr_accessor :margin_box
108
+ attr_reader :margins, :y
109
+ attr_accessor :page_number
110
+
111
+ # @group Extension Attributes
112
+
113
+ attr_accessor :text_formatter
114
+
115
+ # @group Stable API
116
+
93
117
  # Creates and renders a PDF document.
94
118
  #
95
119
  # When using the implicit block form, Prawn will evaluate the block
@@ -117,32 +141,37 @@ module Prawn
117
141
  # pdf.draw_text content, :at => [200,720], :size => 32
118
142
  # end
119
143
  #
120
- def self.generate(filename,options={},&block)
121
- pdf = new(options,&block)
144
+ def self.generate(filename, options = {}, &block)
145
+ pdf = new(options, &block)
122
146
  pdf.render_file(filename)
123
147
  end
124
148
 
125
149
  # Creates a new PDF Document. The following options are available (with
126
150
  # the default values marked in [])
127
151
  #
128
- # <tt>:page_size</tt>:: One of the Document::PageGeometry sizes [LETTER]
152
+ # <tt>:page_size</tt>:: One of the PDF::Core::PageGeometry sizes [LETTER]
129
153
  # <tt>:page_layout</tt>:: Either <tt>:portrait</tt> or <tt>:landscape</tt>
130
154
  # <tt>:margin</tt>:: Sets the margin on all sides in points [0.5 inch]
131
155
  # <tt>:left_margin</tt>:: Sets the left margin in points [0.5 inch]
132
156
  # <tt>:right_margin</tt>:: Sets the right margin in points [0.5 inch]
133
157
  # <tt>:top_margin</tt>:: Sets the top margin in points [0.5 inch]
134
158
  # <tt>:bottom_margin</tt>:: Sets the bottom margin in points [0.5 inch]
135
- # <tt>:skip_page_creation</tt>:: Creates a document without starting the first page [false]
136
- # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
137
- # <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
138
- # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
159
+ # <tt>:skip_page_creation</tt>:: Creates a document without starting the
160
+ # first page [false]
161
+ # <tt>:compress</tt>:: Compresses content streams before rendering them
162
+ # [false]
163
+ # <tt>:background</tt>:: An image path to be used as background on all pages
164
+ # [nil]
139
165
  # <tt>:background_scale</tt>:: Backgound image scale [1] [nil]
140
- # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
141
- # <tt>:template</tt>:: The path to an existing PDF file to use as a template [nil]
142
- # <tt>:text_formatter</tt>: The text formatter to use for <tt>:inline_format</tt>ted text [Prawn::Text::Formatted::Parser]
166
+ # <tt>:info</tt>:: Generic hash allowing for custom metadata properties
167
+ # [nil]
168
+ # <tt>:text_formatter</tt>: The text formatter to use for
169
+ # <tt>:inline_format</tt>ted text
170
+ # [Prawn::Text::Formatted::Parser]
143
171
  #
144
- # Setting e.g. the :margin to 100 points and the :left_margin to 50 will result in margins
145
- # of 100 points on every side except for the left, where it will be 50.
172
+ # Setting e.g. the :margin to 100 points and the :left_margin to 50 will
173
+ # result in margins of 100 points on every side except for the left, where
174
+ # it will be 50.
146
175
  #
147
176
  # The :margin can also be an array much like CSS shorthand:
148
177
  #
@@ -153,8 +182,8 @@ module Prawn
153
182
  # # Top is 10, right is 20, bottom is 30, left is 40.
154
183
  # :margin => [10, 20, 30, 40]
155
184
  #
156
- # Additionally, :page_size can be specified as a simple two value array giving
157
- # the width and height of the document you need in PDF Points.
185
+ # Additionally, :page_size can be specified as a simple two value array
186
+ # giving the width and height of the document you need in PDF Points.
158
187
  #
159
188
  # Usage:
160
189
  #
@@ -162,54 +191,47 @@ module Prawn
162
191
  # pdf = Prawn::Document.new
163
192
  #
164
193
  # # New document, A4 paper, landscaped
165
- # pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
194
+ # pdf = Prawn::Document.new(page_size: "A4", page_layout: :landscape)
166
195
  #
167
196
  # # New document, Custom size
168
- # pdf = Prawn::Document.new(:page_size => [200, 300])
197
+ # pdf = Prawn::Document.new(page_size: [200, 300])
169
198
  #
170
199
  # # New document, with background
171
- # pdf = Prawn::Document.new(:background => "#{Prawn::DATADIR}/images/pigs.jpg")
200
+ # pdf = Prawn::Document.new(
201
+ # background: "#{Prawn::DATADIR}/images/pigs.jpg"
202
+ # )
172
203
  #
173
- def initialize(options={},&block)
204
+ def initialize(options = {}, &block)
174
205
  options = options.dup
175
206
 
176
- Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
177
- :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
178
- :compress, :skip_encoding, :background, :info,
179
- :optimize_objects, :template, :text_formatter], options
207
+ Prawn.verify_options VALID_OPTIONS, options
180
208
 
181
209
  # need to fix, as the refactoring breaks this
182
210
  # raise NotImplementedError if options[:skip_page_creation]
183
211
 
184
212
  self.class.extensions.reverse_each { |e| extend e }
185
- @internal_state = PDF::Core::DocumentState.new(options)
186
- @internal_state.populate_pages_from_store(self)
187
- min_version(state.store.min_version) if state.store.min_version
213
+ self.state = PDF::Core::DocumentState.new(options)
214
+ state.populate_pages_from_store(self)
215
+ renderer.min_version(state.store.min_version) if state.store.min_version
216
+
217
+ renderer.min_version(1.6) if options[:print_scaling] == :none
188
218
 
189
219
  @background = options[:background]
190
220
  @background_scale = options[:background_scale] || 1
191
- @font_size = 12
221
+ @font_size = 12
192
222
 
193
- @bounding_box = nil
194
- @margin_box = nil
223
+ @bounding_box = nil
224
+ @margin_box = nil
195
225
 
196
226
  @page_number = 0
197
227
 
198
- @text_formatter = options.delete(:text_formatter) || Text::Formatted::Parser
228
+ @text_formatter = options.delete(:text_formatter) ||
229
+ Text::Formatted::Parser
199
230
 
200
231
  options[:size] = options.delete(:page_size)
201
232
  options[:layout] = options.delete(:page_layout)
202
233
 
203
- if options[:template]
204
- fresh_content_streams(options)
205
- go_to_page(1)
206
- else
207
- if options[:skip_page_creation] || options[:template]
208
- start_new_page(options.merge(:orphan => true))
209
- else
210
- start_new_page(options)
211
- end
212
- end
234
+ initialize_first_page(options)
213
235
 
214
236
  @bounding_box = @margin_box
215
237
 
@@ -218,19 +240,7 @@ module Prawn
218
240
  end
219
241
  end
220
242
 
221
- attr_accessor :margin_box
222
- attr_reader :margins, :y
223
- attr_writer :font_size
224
- attr_accessor :page_number
225
- attr_accessor :text_formatter
226
-
227
- def state
228
- @internal_state
229
- end
230
-
231
- def page
232
- state.page
233
- end
243
+ # @group Stable API
234
244
 
235
245
  # Creates and advances to a new page in the document.
236
246
  #
@@ -242,31 +252,30 @@ module Prawn
242
252
  # pdf.start_new_page(:left_margin => 50, :right_margin => 50)
243
253
  # pdf.start_new_page(:margin => 100)
244
254
  #
245
- # A template for a page can be specified by pointing to the path of and existing pdf.
246
- # One can also specify which page of the template which defaults otherwise to 1.
247
- #
248
- # pdf.start_new_page(:template => multipage_template.pdf, :template_page => 2)
249
- #
250
- # Note: templates get indexed by either the object_id of the filename or stream
251
- # entered so that if you reuse the same template multiple times be sure to use the
252
- # same instance for more efficient use of resources and smaller rendered pdfs.
253
255
  def start_new_page(options = {})
254
- if last_page = state.page
255
- last_page_size = last_page.size
256
- last_page_layout = last_page.layout
257
- last_page_margins = last_page.margins
256
+ last_page = state.page
257
+ if last_page
258
+ last_page_size = last_page.size
259
+ last_page_layout = last_page.layout
260
+ last_page_margins = last_page.margins.dup
258
261
  end
259
262
 
260
- page_options = {:size => options[:size] || last_page_size,
261
- :layout => options[:layout] || last_page_layout,
262
- :margins => last_page_margins}
263
+ page_options = {
264
+ size: options[:size] || last_page_size,
265
+ layout: options[:layout] || last_page_layout,
266
+ margins: last_page_margins
267
+ }
263
268
  if last_page
264
- new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
265
- #erase the color space so that it gets reset on new page for fussy pdf-readers
266
- new_graphic_state.color_space = {} if new_graphic_state
267
- page_options.merge!(:graphic_state => new_graphic_state)
269
+ if last_page.graphic_state
270
+ new_graphic_state = last_page.graphic_state.dup
271
+ end
272
+
273
+ # erase the color space so that it gets reset on new page for fussy
274
+ # pdf-readers
275
+ new_graphic_state&.color_space = {}
276
+
277
+ page_options[:graphic_state] = new_graphic_state
268
278
  end
269
- merge_template_options(page_options, options) if options[:template]
270
279
 
271
280
  state.page = PDF::Core::Page.new(self, page_options)
272
281
 
@@ -279,15 +288,17 @@ module Prawn
279
288
  @bounding_box = @margin_box
280
289
  end
281
290
 
282
- state.page.new_content_stream if options[:template]
283
- use_graphic_settings(options[:template])
284
- forget_text_rendering_mode! if options[:template]
291
+ use_graphic_settings
285
292
 
286
293
  unless options[:orphan]
287
294
  state.insert_page(state.page, @page_number)
288
295
  @page_number += 1
289
296
 
290
- canvas { image(@background, :scale => @background_scale, :at => bounds.top_left) } if @background
297
+ if @background
298
+ canvas do
299
+ image(@background, scale: @background_scale, at: bounds.top_left)
300
+ end
301
+ end
291
302
  @y = @bounding_box.absolute_top
292
303
 
293
304
  float do
@@ -296,6 +307,26 @@ module Prawn
296
307
  end
297
308
  end
298
309
 
310
+ # Remove page of the document by index
311
+ #
312
+ # pdf = Prawn::Document.new
313
+ # pdf.page_count #=> 1
314
+ # 3.times { pdf.start_new_page }
315
+ # pdf.page_count #=> 4
316
+ # pdf.delete_page(-1)
317
+ # pdf.page_count #=> 3
318
+ #
319
+ def delete_page(index)
320
+ return false if index.abs > (state.pages.count - 1)
321
+
322
+ state.pages.delete_at(index)
323
+
324
+ state.store.pages.data[:Kids].delete_at(index)
325
+ state.store.pages.data[:Count] -= 1
326
+ @page_number -= 1
327
+ true
328
+ end
329
+
299
330
  # Returns the number of pages in the document
300
331
  #
301
332
  # pdf = Prawn::Document.new
@@ -312,9 +343,9 @@ module Prawn
312
343
  #
313
344
  # See Prawn::Document#number_pages for a sample usage of this capability.
314
345
  #
315
- def go_to_page(k)
316
- @page_number = k
317
- state.page = state.pages[k-1]
346
+ def go_to_page(page_number)
347
+ @page_number = page_number
348
+ state.page = state.pages[page_number - 1]
318
349
  generate_margin_box
319
350
  @y = @bounding_box.absolute_top
320
351
  end
@@ -361,20 +392,13 @@ module Prawn
361
392
  # Renders the PDF document to string.
362
393
  # Pass an open file descriptor to render to file.
363
394
  #
364
- def render(output = StringIO.new)
365
- finalize_all_page_contents
366
-
367
- render_header(output)
368
- render_body(output)
369
- render_xref(output)
370
- render_trailer(output)
371
- if output.instance_of?(StringIO)
372
- str = output.string
373
- str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
374
- return str
375
- else
376
- return nil
395
+ def render(*arguments, &block)
396
+ (1..page_count).each do |i|
397
+ go_to_page i
398
+ repeaters.each { |r| r.run(i) }
377
399
  end
400
+
401
+ renderer.render(*arguments, &block)
378
402
  end
379
403
 
380
404
  # Renders the PDF document to file.
@@ -382,8 +406,7 @@ module Prawn
382
406
  # pdf.render_file "foo.pdf"
383
407
  #
384
408
  def render_file(filename)
385
- Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
386
- File.open(filename,mode) { |f| render(f) }
409
+ File.open(filename, 'wb') { |f| render(f) }
387
410
  end
388
411
 
389
412
  # The bounds method returns the current bounding box you are currently in,
@@ -392,14 +415,15 @@ module Prawn
392
415
  # block, the box defined by that call will be returned instead of the
393
416
  # document margin box.
394
417
  #
395
- # Another important point about bounding boxes is that all x and y measurements
396
- # within a bounding box code block are relative to the bottom left corner of the
397
- # bounding box.
418
+ # Another important point about bounding boxes is that all x and
419
+ # y measurements within a bounding box code block are relative to the bottom
420
+ # left corner of the bounding box.
398
421
  #
399
422
  # For example:
400
423
  #
401
424
  # Prawn::Document.new do
402
- # # In the default "margin box" of a Prawn document of 0.5in along each edge
425
+ # # In the default "margin box" of a Prawn document of 0.5in along each
426
+ # # edge
403
427
  #
404
428
  # # Draw a border around the page (the manual way)
405
429
  # stroke do
@@ -419,14 +443,15 @@ module Prawn
419
443
 
420
444
  # Returns the innermost non-stretchy bounding box.
421
445
  #
446
+ # @private
422
447
  def reference_bounds
423
448
  @bounding_box.reference_bounds
424
449
  end
425
450
 
426
451
  # Sets Document#bounds to the BoundingBox provided. See above for a brief
427
452
  # description of what a bounding box is. This function is useful if you
428
- # really need to change the bounding box manually, but usually, just entering
429
- # and exiting bounding box code blocks is good enough.
453
+ # really need to change the bounding box manually, but usually, just
454
+ # entering and exiting bounding box code blocks is good enough.
430
455
  #
431
456
  def bounds=(bounding_box)
432
457
  @bounding_box = bounding_box
@@ -435,15 +460,15 @@ module Prawn
435
460
  # Moves up the document by n points relative to the current position inside
436
461
  # the current bounding box.
437
462
  #
438
- def move_up(n)
439
- self.y += n
463
+ def move_up(amount)
464
+ self.y += amount
440
465
  end
441
466
 
442
- # Moves down the document by n points relative to the current position inside
443
- # the current bounding box.
467
+ # Moves down the document by n points relative to the current position
468
+ # inside the current bounding box.
444
469
  #
445
- def move_down(n)
446
- self.y -= n
470
+ def move_down(amount)
471
+ self.y -= amount
447
472
  end
448
473
 
449
474
  # Moves down the document and then executes a block.
@@ -487,7 +512,6 @@ module Prawn
487
512
  move_down(y)
488
513
  end
489
514
 
490
-
491
515
  # Indents the specified number of PDF points for the duration of the block
492
516
  #
493
517
  # pdf.text "some text"
@@ -504,119 +528,117 @@ module Prawn
504
528
  bounds.indent(left, right, &block)
505
529
  end
506
530
 
507
-
508
- def mask(*fields) # :nodoc:
509
- # Stores the current state of the named attributes, executes the block, and
510
- # then restores the original values after the block has executed.
511
- # -- I will remove the nodoc if/when this feature is a little less hacky
512
- stored = {}
513
- fields.each { |f| stored[f] = send(f) }
514
- yield
515
- fields.each { |f| send("#{f}=", stored[f]) }
516
- end
517
-
518
- # Attempts to group the given block vertically within the current context.
519
- # First attempts to render it in the current position on the current page.
520
- # If that attempt overflows, it is tried anew after starting a new context
521
- # (page or column). Returns a logically true value if the content fits in
522
- # one page/column, false if a new page or column was needed.
523
- #
524
- # Raises CannotGroup if the provided content is too large to fit alone in
525
- # the current page or column.
526
- #
527
- def group(second_attempt=false)
528
- old_bounding_box = @bounding_box
529
- @bounding_box = SimpleDelegator.new(@bounding_box)
530
-
531
- def @bounding_box.move_past_bottom
532
- raise RollbackTransaction
533
- end
534
-
535
- success = transaction { yield }
536
-
537
- @bounding_box = old_bounding_box
538
-
539
- unless success
540
- raise Prawn::Errors::CannotGroup if second_attempt
541
- old_bounding_box.move_past_bottom
542
- group(second_attempt=true) { yield }
543
- end
544
-
545
- success
546
- end
547
-
548
- # Places a text box on specified pages for page numbering. This should be called
549
- # towards the end of document creation, after all your content is already in
550
- # place. In your template string, <page> refers to the current page, and
551
- # <total> refers to the total amount of pages in the document. Page numbering should
552
- # occur at the end of your Prawn::Document.generate block because the method iterates
553
- # through existing pages after they are created.
531
+ # Places a text box on specified pages for page numbering. This should be
532
+ # called towards the end of document creation, after all your content is
533
+ # already in place. In your template string, <page> refers to the current
534
+ # page, and <total> refers to the total amount of pages in the document.
535
+ # Page numbering should occur at the end of your Prawn::Document.generate
536
+ # block because the method iterates through existing pages after they are
537
+ # created.
554
538
  #
555
539
  # Parameters are:
556
540
  #
557
541
  # <tt>string</tt>:: Template string for page number wording.
558
542
  # Should include '<page>' and, optionally, '<total>'.
559
543
  # <tt>options</tt>:: A hash for page numbering and text box options.
560
- # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
561
- # Refer to the method 'page_match?'
544
+ # <tt>:page_filter</tt>:: A filter to specify which pages to place page
545
+ # numbers on. Refer to the method 'page_match?'
562
546
  # <tt>:start_count_at</tt>:: The starting count to increment pages from.
563
- # <tt>:total_pages</tt>:: If provided, will replace <total> with the value given.
564
- # Useful to override the total number of pages when using
565
- # the start_count_at option.
547
+ # <tt>:total_pages</tt>:: If provided, will replace <total> with the
548
+ # value given. Useful to override the total
549
+ # number of pages when using the start_count_at
550
+ # option.
566
551
  # <tt>:color</tt>:: Text fill color.
567
552
  #
568
- # Please refer to Prawn::Text::text_box for additional options concerning text
569
- # formatting and placement.
570
- #
571
- # Example: Print page numbers on every page except for the first. Start counting from
572
- # five.
553
+ # Please refer to Prawn::Text::text_box for additional options
554
+ # concerning text formatting and placement.
573
555
  #
574
- # Prawn::Document.generate("page_with_numbering.pdf") do
575
- # number_pages "<page> in a total of <total>",
576
- # {:start_count_at => 5,
577
- # :page_filter => lambda{ |pg| pg != 1 },
578
- # :at => [bounds.right - 50, 0],
579
- # :align => :right,
580
- # :size => 14}
581
- # end
556
+ # Example:
557
+ # Print page numbers on every page except for the first. Start counting
558
+ # from five.
559
+ #
560
+ # Prawn::Document.generate("page_with_numbering.pdf") do
561
+ # number_pages "<page> in a total of <total>", {
562
+ # start_count_at: 5,
563
+ # page_filter: lambda { |pg| pg != 1 },
564
+ # at: [bounds.right - 50, 0],
565
+ # align: :right,
566
+ # size: 14
567
+ # }
568
+ # end
582
569
  #
583
- def number_pages(string, options={})
570
+ def number_pages(string, options = {})
584
571
  opts = options.dup
585
572
  start_count_at = opts.delete(:start_count_at).to_i
586
- page_filter = if opts.has_key?(:page_filter)
587
- opts.delete(:page_filter)
588
- else
589
- :all
590
- end
573
+
574
+ page_filter =
575
+ if opts.key?(:page_filter)
576
+ opts.delete(:page_filter)
577
+ else
578
+ :all
579
+ end
580
+
591
581
  total_pages = opts.delete(:total_pages)
592
582
  txtcolor = opts.delete(:color)
593
583
  # An explicit height so that we can draw page numbers in the margins
594
- opts[:height] = 50 unless opts.has_key?(:height)
584
+ opts[:height] = 50 unless opts.key?(:height)
595
585
 
596
586
  start_count = false
597
587
  pseudopage = 0
598
588
  (1..page_count).each do |p|
599
589
  unless start_count
600
- pseudopage = case start_count_at
601
- when 0
602
- 1
603
- else
604
- start_count_at.to_i
605
- end
590
+ pseudopage =
591
+ case start_count_at
592
+ when 0
593
+ 1
594
+ else
595
+ start_count_at.to_i
596
+ end
606
597
  end
607
598
  if page_match?(page_filter, p)
608
599
  go_to_page(p)
609
- # have to use fill_color here otherwise text reverts back to default fill color
600
+ # have to use fill_color here otherwise text reverts back to default
601
+ # fill color
610
602
  fill_color txtcolor unless txtcolor.nil?
611
603
  total_pages = total_pages.nil? ? page_count : total_pages
612
- str = string.gsub("<page>","#{pseudopage}").gsub("<total>","#{total_pages}")
604
+ str = string.gsub('<page>', pseudopage.to_s)
605
+ .gsub('<total>', total_pages.to_s)
613
606
  text_box str, opts
614
- start_count = true # increment page count as soon as first match found
607
+ start_count = true # increment page count as soon as first match found
615
608
  end
616
609
  pseudopage += 1 if start_count
617
610
  end
618
611
  end
619
612
 
613
+ # @group Experimental API
614
+
615
+ # Attempts to group the given block vertically within the current context.
616
+ # First attempts to render it in the current position on the current page.
617
+ # If that attempt overflows, it is tried anew after starting a new context
618
+ # (page or column). Returns a logically true value if the content fits in
619
+ # one page/column, false if a new page or column was needed.
620
+ #
621
+ # Raises CannotGroup if the provided content is too large to fit alone in
622
+ # the current page or column.
623
+ #
624
+ # @private
625
+ def group(*_arguments)
626
+ raise NotImplementedError,
627
+ 'Document#group has been disabled because its implementation ' \
628
+ 'lead to corrupted documents whenever a page boundary was ' \
629
+ 'crossed. We will try to work on reimplementing it in a ' \
630
+ 'future release'
631
+ end
632
+
633
+ # @private
634
+ def transaction
635
+ raise NotImplementedError,
636
+ 'Document#transaction has been disabled because its implementation ' \
637
+ 'lead to corrupted documents whenever a page boundary was ' \
638
+ 'crossed. We will try to work on reimplementing it in a ' \
639
+ 'future release'
640
+ end
641
+
620
642
  # Provides a way to execute a block of code repeatedly based on a
621
643
  # page_filter.
622
644
  #
@@ -632,9 +654,9 @@ module Prawn
632
654
  when :all
633
655
  true
634
656
  when :odd
635
- page_number % 2 == 1
657
+ page_number.odd?
636
658
  when :even
637
- page_number % 2 == 0
659
+ page_number.even?
638
660
  when Range, Array
639
661
  page_filter.include?(page_number)
640
662
  when Proc
@@ -642,26 +664,45 @@ module Prawn
642
664
  end
643
665
  end
644
666
 
667
+ # @private
645
668
 
646
- # Returns true if content streams will be compressed before rendering,
647
- # false otherwise
648
- #
649
- def compression_enabled?
650
- !!state.compress
669
+ def mask(*fields)
670
+ # Stores the current state of the named attributes, executes the block,
671
+ # and then restores the original values after the block has executed.
672
+ # -- I will remove the nodoc if/when this feature is a little less hacky
673
+ stored = {}
674
+ fields.each { |f| stored[f] = public_send(f) }
675
+ yield
676
+ fields.each { |f| public_send("#{f}=", stored[f]) }
651
677
  end
652
678
 
653
- private
679
+ # @group Extension API
680
+
681
+ def initialize_first_page(options)
682
+ if options[:skip_page_creation]
683
+ start_new_page(options.merge(orphan: true))
684
+ else
685
+ start_new_page(options)
686
+ end
687
+ end
688
+
689
+ ## Internals. Don't depend on them!
690
+
691
+ # @private
692
+ attr_accessor :state
654
693
 
655
- def merge_template_options(page_options, options)
656
- object_id = state.store.import_page(options[:template], options[:template_page] || 1)
657
- page_options.merge!(:object_id => object_id, :page_template => true)
694
+ # @private
695
+ def page
696
+ state.page
658
697
  end
659
698
 
660
- # setting override_settings to true ensures that a new graphic state does not end up using
661
- # previous settings especially from imported template streams
699
+ private
700
+
701
+ # setting override_settings to true ensures that a new graphic state does
702
+ # not end up using previous settings.
662
703
  def use_graphic_settings(override_settings = false)
663
- set_fill_color if current_fill_color != "000000" || override_settings
664
- set_stroke_color if current_stroke_color != "000000" || override_settings
704
+ set_fill_color if current_fill_color != '000000' || override_settings
705
+ set_stroke_color if current_stroke_color != '000000' || override_settings
665
706
  write_line_width if line_width != 1 || override_settings
666
707
  write_stroke_cap_style if cap_style != :butt || override_settings
667
708
  write_stroke_join_style if join_style != :miter || override_settings
@@ -670,14 +711,16 @@ module Prawn
670
711
 
671
712
  def generate_margin_box
672
713
  old_margin_box = @margin_box
673
- page = state.page
714
+ page = state.page
674
715
 
675
716
  @margin_box = BoundingBox.new(
676
717
  self,
677
- nil, # margin box has no parent
678
- [ page.margins[:left], page.dimensions[-1] - page.margins[:top] ] ,
679
- :width => page.dimensions[-2] - (page.margins[:left] + page.margins[:right]),
680
- :height => page.dimensions[-1] - (page.margins[:top] + page.margins[:bottom])
718
+ nil, # margin box has no parent
719
+ [page.margins[:left], page.dimensions[-1] - page.margins[:top]],
720
+ width: page.dimensions[-2] -
721
+ (page.margins[:left] + page.margins[:right]),
722
+ height: page.dimensions[-1] -
723
+ (page.margins[:top] + page.margins[:bottom])
681
724
  )
682
725
 
683
726
  # This check maintains indentation settings across page breaks
@@ -688,32 +731,30 @@ module Prawn
688
731
 
689
732
  # we must update bounding box if not flowing from the previous page
690
733
  #
691
- # FIXME: This may have a bug where the old margin is restored
692
- # when the bounding box exits.
693
- @bounding_box = @margin_box if old_margin_box == @bounding_box
734
+ @bounding_box = @margin_box unless @bounding_box&.parent
694
735
  end
695
736
 
696
737
  def apply_margin_options(options)
697
- if options[:margin]
698
- # Treat :margin as CSS shorthand with 1-4 values.
699
- margin = Array(options[:margin])
700
- positions = { 4 => [0,1,2,3], 3 => [0,1,2,1],
701
- 2 => [0,1,0,1], 1 => [0,0,0,0] }[margin.length]
702
-
703
- [:top, :right, :bottom, :left].zip(positions).each do |p,i|
704
- options[:"#{p}_margin"] ||= margin[i]
705
- end
706
- end
707
-
708
- [:left,:right,:top,:bottom].each do |side|
709
- if margin = options[:"#{side}_margin"]
710
- state.page.margins[side] = margin
711
- end
738
+ sides = %i[top right bottom left]
739
+ margin = Array(options[:margin])
740
+
741
+ # Treat :margin as CSS shorthand with 1-4 values.
742
+ positions = {
743
+ 4 => [0, 1, 2, 3],
744
+ 3 => [0, 1, 2, 1],
745
+ 2 => [0, 1, 0, 1],
746
+ 1 => [0, 0, 0, 0],
747
+ 0 => []
748
+ }[margin.length]
749
+
750
+ sides.zip(positions).each do |side, pos|
751
+ new_margin = options[:"#{side}_margin"] || (margin[pos] if pos)
752
+ state.page.margins[side] = new_margin if new_margin
712
753
  end
713
754
  end
714
755
 
715
756
  def font_metric_cache #:nodoc:
716
- @font_metric_cache ||= FontMetricCache.new( self )
757
+ @font_metric_cache ||= FontMetricCache.new(self)
717
758
  end
718
759
  end
719
760
  end