prawn 2.1.0 → 2.2.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 (278) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +1 -9
  5. data/Rakefile +12 -22
  6. data/lib/prawn.rb +29 -48
  7. data/lib/prawn/document.rb +148 -123
  8. data/lib/prawn/document/bounding_box.rb +33 -26
  9. data/lib/prawn/document/column_box.rb +5 -7
  10. data/lib/prawn/document/internals.rb +6 -6
  11. data/lib/prawn/document/span.rb +20 -17
  12. data/lib/prawn/encoding.rb +65 -67
  13. data/lib/prawn/errors.rb +10 -7
  14. data/lib/prawn/font.rb +78 -62
  15. data/lib/prawn/font/afm.rb +93 -66
  16. data/lib/prawn/font/dfont.rb +2 -10
  17. data/lib/prawn/font/ttc.rb +34 -0
  18. data/lib/prawn/font/ttf.rb +73 -65
  19. data/lib/prawn/font_metric_cache.rb +9 -8
  20. data/lib/prawn/graphics.rb +110 -70
  21. data/lib/prawn/graphics/blend_mode.rb +7 -8
  22. data/lib/prawn/graphics/cap_style.rb +2 -4
  23. data/lib/prawn/graphics/color.rb +23 -26
  24. data/lib/prawn/graphics/dash.rb +22 -12
  25. data/lib/prawn/graphics/join_style.rb +8 -4
  26. data/lib/prawn/graphics/patterns.rb +185 -96
  27. data/lib/prawn/graphics/transformation.rb +11 -9
  28. data/lib/prawn/graphics/transparency.rb +15 -13
  29. data/lib/prawn/grid.rb +20 -20
  30. data/lib/prawn/image_handler.rb +4 -6
  31. data/lib/prawn/images.rb +22 -15
  32. data/lib/prawn/images/image.rb +0 -1
  33. data/lib/prawn/images/jpg.rb +26 -22
  34. data/lib/prawn/images/png.rb +60 -57
  35. data/lib/prawn/measurement_extensions.rb +8 -9
  36. data/lib/prawn/measurements.rb +14 -15
  37. data/lib/prawn/outline.rb +96 -78
  38. data/lib/prawn/repeater.rb +12 -10
  39. data/lib/prawn/security.rb +66 -48
  40. data/lib/prawn/security/arcfour.rb +1 -3
  41. data/lib/prawn/soft_mask.rb +23 -25
  42. data/lib/prawn/stamp.rb +16 -12
  43. data/lib/prawn/text.rb +59 -45
  44. data/lib/prawn/text/box.rb +9 -8
  45. data/lib/prawn/text/formatted.rb +4 -6
  46. data/lib/prawn/text/formatted/arranger.rb +51 -30
  47. data/lib/prawn/text/formatted/box.rb +112 -88
  48. data/lib/prawn/text/formatted/fragment.rb +10 -15
  49. data/lib/prawn/text/formatted/line_wrap.rb +118 -61
  50. data/lib/prawn/text/formatted/parser.rb +134 -110
  51. data/lib/prawn/text/formatted/wrap.rb +42 -32
  52. data/lib/prawn/transformation_stack.rb +3 -4
  53. data/lib/prawn/utilities.rb +6 -21
  54. data/lib/prawn/version.rb +1 -3
  55. data/lib/prawn/view.rb +4 -2
  56. data/manual/basic_concepts/adding_pages.rb +4 -7
  57. data/manual/basic_concepts/basic_concepts.rb +29 -22
  58. data/manual/basic_concepts/creation.rb +8 -11
  59. data/manual/basic_concepts/cursor.rb +2 -5
  60. data/manual/basic_concepts/measurement.rb +3 -6
  61. data/manual/basic_concepts/origin.rb +3 -6
  62. data/manual/basic_concepts/other_cursor_helpers.rb +9 -12
  63. data/manual/basic_concepts/view.rb +20 -16
  64. data/manual/bounding_box/bounding_box.rb +27 -24
  65. data/manual/bounding_box/bounds.rb +9 -12
  66. data/manual/bounding_box/canvas.rb +2 -5
  67. data/manual/bounding_box/creation.rb +4 -7
  68. data/manual/bounding_box/indentation.rb +12 -15
  69. data/manual/bounding_box/nesting.rb +22 -17
  70. data/manual/bounding_box/russian_boxes.rb +8 -9
  71. data/manual/bounding_box/stretchy.rb +10 -13
  72. data/manual/contents.rb +26 -22
  73. data/manual/cover.rb +22 -20
  74. data/manual/document_and_page_options/background.rb +9 -13
  75. data/manual/document_and_page_options/document_and_page_options.rb +23 -20
  76. data/manual/document_and_page_options/metadata.rb +16 -16
  77. data/manual/document_and_page_options/page_margins.rb +16 -20
  78. data/manual/document_and_page_options/page_size.rb +11 -12
  79. data/manual/document_and_page_options/print_scaling.rb +15 -15
  80. data/manual/example_helper.rb +2 -4
  81. data/manual/graphics/blend_mode.rb +10 -9
  82. data/manual/graphics/circle_and_ellipse.rb +2 -5
  83. data/manual/graphics/color.rb +5 -9
  84. data/manual/graphics/common_lines.rb +5 -8
  85. data/manual/graphics/fill_and_stroke.rb +2 -5
  86. data/manual/graphics/fill_rules.rb +7 -10
  87. data/manual/graphics/gradients.rb +25 -21
  88. data/manual/graphics/graphics.rb +49 -43
  89. data/manual/graphics/helper.rb +10 -9
  90. data/manual/graphics/line_width.rb +5 -7
  91. data/manual/graphics/lines_and_curves.rb +5 -8
  92. data/manual/graphics/polygon.rb +4 -8
  93. data/manual/graphics/rectangle.rb +2 -5
  94. data/manual/graphics/rotate.rb +4 -7
  95. data/manual/graphics/scale.rb +12 -15
  96. data/manual/graphics/soft_masks.rb +1 -4
  97. data/manual/graphics/stroke_cap.rb +3 -6
  98. data/manual/graphics/stroke_dash.rb +9 -12
  99. data/manual/graphics/stroke_join.rb +2 -5
  100. data/manual/graphics/translate.rb +7 -10
  101. data/manual/graphics/transparency.rb +5 -8
  102. data/manual/how_to_read_this_manual.rb +4 -6
  103. data/manual/images/absolute_position.rb +4 -7
  104. data/manual/images/fit.rb +5 -8
  105. data/manual/images/horizontal.rb +6 -9
  106. data/manual/images/images.rb +25 -23
  107. data/manual/images/plain_image.rb +3 -6
  108. data/manual/images/scale.rb +7 -10
  109. data/manual/images/vertical.rb +10 -13
  110. data/manual/images/width_and_height.rb +8 -11
  111. data/manual/layout/boxes.rb +3 -6
  112. data/manual/layout/content.rb +5 -8
  113. data/manual/layout/layout.rb +16 -16
  114. data/manual/layout/simple_grid.rb +4 -7
  115. data/manual/outline/add_subsection_to.rb +18 -21
  116. data/manual/outline/insert_section_after.rb +13 -16
  117. data/manual/outline/outline.rb +19 -17
  118. data/manual/outline/sections_and_pages.rb +15 -18
  119. data/manual/repeatable_content/alternate_page_numbering.rb +19 -17
  120. data/manual/repeatable_content/page_numbering.rb +15 -16
  121. data/manual/repeatable_content/repeatable_content.rb +23 -19
  122. data/manual/repeatable_content/repeater.rb +12 -15
  123. data/manual/repeatable_content/stamp.rb +12 -15
  124. data/manual/security/encryption.rb +7 -10
  125. data/manual/security/permissions.rb +17 -14
  126. data/manual/security/security.rb +17 -16
  127. data/manual/table.rb +2 -4
  128. data/manual/text/alignment.rb +14 -17
  129. data/manual/text/color.rb +10 -11
  130. data/manual/text/column_box.rb +5 -8
  131. data/manual/text/fallback_fonts.rb +23 -21
  132. data/manual/text/font.rb +9 -12
  133. data/manual/text/font_size.rb +11 -14
  134. data/manual/text/font_style.rb +4 -7
  135. data/manual/text/formatted_callbacks.rb +23 -21
  136. data/manual/text/formatted_text.rb +31 -25
  137. data/manual/text/free_flowing_text.rb +18 -21
  138. data/manual/text/inline.rb +16 -19
  139. data/manual/text/kerning_and_character_spacing.rb +12 -15
  140. data/manual/text/leading.rb +5 -8
  141. data/manual/text/line_wrapping.rb +33 -17
  142. data/manual/text/paragraph_indentation.rb +11 -14
  143. data/manual/text/positioned_text.rb +13 -16
  144. data/manual/text/registering_families.rb +16 -19
  145. data/manual/text/rendering_and_color.rb +7 -10
  146. data/manual/text/right_to_left_text.rb +24 -19
  147. data/manual/text/rotation.rb +26 -23
  148. data/manual/text/single_usage.rb +6 -9
  149. data/manual/text/text.rb +56 -52
  150. data/manual/text/text_box_excess.rb +18 -17
  151. data/manual/text/text_box_extensions.rb +16 -15
  152. data/manual/text/text_box_overflow.rb +15 -18
  153. data/manual/text/utf8.rb +9 -12
  154. data/manual/text/win_ansi_charset.rb +18 -19
  155. data/prawn.gemspec +37 -27
  156. data/spec/extensions/encoding_helpers.rb +0 -2
  157. data/spec/manual_spec.rb +33 -0
  158. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  159. data/spec/prawn/document/column_box_spec.rb +73 -0
  160. data/spec/prawn/document/security_spec.rb +173 -0
  161. data/spec/prawn/document_annotations_spec.rb +74 -0
  162. data/spec/prawn/document_destinations_spec.rb +13 -0
  163. data/spec/prawn/document_grid_spec.rb +96 -0
  164. data/spec/prawn/document_reference_spec.rb +25 -0
  165. data/spec/prawn/document_span_spec.rb +34 -0
  166. data/spec/prawn/document_spec.rb +751 -0
  167. data/spec/prawn/font_metric_cache_spec.rb +52 -0
  168. data/spec/prawn/font_spec.rb +513 -0
  169. data/spec/prawn/graphics/blend_mode_spec.rb +61 -0
  170. data/spec/prawn/graphics/transparency_spec.rb +79 -0
  171. data/spec/prawn/graphics_spec.rb +817 -0
  172. data/spec/prawn/graphics_stroke_styles_spec.rb +227 -0
  173. data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +13 -15
  174. data/spec/prawn/images/jpg_spec.rb +18 -0
  175. data/spec/prawn/images/png_spec.rb +281 -0
  176. data/spec/prawn/images_spec.rb +170 -0
  177. data/spec/prawn/measurements_extensions_spec.rb +22 -0
  178. data/spec/prawn/outline_spec.rb +408 -0
  179. data/spec/prawn/repeater_spec.rb +163 -0
  180. data/spec/prawn/soft_mask_spec.rb +72 -0
  181. data/spec/prawn/stamp_spec.rb +168 -0
  182. data/spec/prawn/text/box_spec.rb +1113 -0
  183. data/spec/prawn/text/formatted/arranger_spec.rb +464 -0
  184. data/spec/prawn/text/formatted/box_spec.rb +825 -0
  185. data/spec/prawn/text/formatted/fragment_spec.rb +341 -0
  186. data/spec/prawn/text/formatted/line_wrap_spec.rb +491 -0
  187. data/spec/prawn/text/formatted/parser_spec.rb +667 -0
  188. data/spec/prawn/text_draw_text_spec.rb +147 -0
  189. data/spec/prawn/text_rendering_mode_spec.rb +42 -0
  190. data/spec/prawn/text_spacing_spec.rb +93 -0
  191. data/spec/prawn/text_spec.rb +601 -0
  192. data/spec/prawn/text_with_inline_formatting_spec.rb +33 -0
  193. data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +21 -20
  194. data/spec/prawn/view_spec.rb +45 -0
  195. data/spec/spec_helper.rb +16 -16
  196. metadata +96 -151
  197. metadata.gz.sig +1 -0
  198. data/data/images/16bit.alpha +0 -0
  199. data/data/images/16bit.color +0 -0
  200. data/data/images/16bit.png +0 -0
  201. data/data/images/arrow.png +0 -0
  202. data/data/images/arrow2.png +0 -0
  203. data/data/images/blend_modes_bottom_layer.jpg +0 -0
  204. data/data/images/blend_modes_top_layer.jpg +0 -0
  205. data/data/images/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/indexed_transparency.png +0 -0
  213. data/data/images/indexed_transparency_alpha.dat +0 -0
  214. data/data/images/indexed_transparency_color.dat +0 -0
  215. data/data/images/letterhead.jpg +0 -0
  216. data/data/images/license.md +0 -8
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.color +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/spec/acceptance/png_spec.rb +0 -35
  244. data/spec/annotations_spec.rb +0 -67
  245. data/spec/blend_mode_spec.rb +0 -71
  246. data/spec/bounding_box_spec.rb +0 -501
  247. data/spec/column_box_spec.rb +0 -59
  248. data/spec/destinations_spec.rb +0 -13
  249. data/spec/document_spec.rb +0 -738
  250. data/spec/font_metric_cache_spec.rb +0 -52
  251. data/spec/font_spec.rb +0 -475
  252. data/spec/formatted_text_arranger_spec.rb +0 -452
  253. data/spec/formatted_text_box_spec.rb +0 -716
  254. data/spec/formatted_text_fragment_spec.rb +0 -299
  255. data/spec/graphics_spec.rb +0 -705
  256. data/spec/grid_spec.rb +0 -95
  257. data/spec/images_spec.rb +0 -167
  258. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  259. data/spec/jpg_spec.rb +0 -23
  260. data/spec/line_wrap_spec.rb +0 -366
  261. data/spec/measurement_units_spec.rb +0 -22
  262. data/spec/outline_spec.rb +0 -409
  263. data/spec/png_spec.rb +0 -257
  264. data/spec/reference_spec.rb +0 -25
  265. data/spec/repeater_spec.rb +0 -154
  266. data/spec/security_spec.rb +0 -151
  267. data/spec/soft_mask_spec.rb +0 -78
  268. data/spec/span_spec.rb +0 -43
  269. data/spec/stamp_spec.rb +0 -179
  270. data/spec/stroke_styles_spec.rb +0 -208
  271. data/spec/text_at_spec.rb +0 -142
  272. data/spec/text_box_spec.rb +0 -1042
  273. data/spec/text_rendering_mode_spec.rb +0 -45
  274. data/spec/text_spacing_spec.rb +0 -93
  275. data/spec/text_spec.rb +0 -543
  276. data/spec/text_with_inline_formatting_spec.rb +0 -35
  277. data/spec/transparency_spec.rb +0 -91
  278. data/spec/view_spec.rb +0 -42
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module EncodingHelpers
4
2
  def win1252_string(str)
5
3
  str.force_encoding(Encoding::Windows_1252)
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'digest/sha2'
3
+
4
+ # rubocop: disable Metrics/LineLength
5
+ MANUAL_HASH =
6
+ case RUBY_ENGINE
7
+ when 'ruby'
8
+ 'b55f154c9093c60f38051c75920c8157c775b946b0c77ffafc0a8a634ad5401e8ceafd0b96942839f82bacd726a690af3fdd1fd9e185616f67c6c0edfcfd0460'
9
+ when 'jruby'
10
+ 'd2eb71ea3ddc35acb185de671a6fa48862ebad5727ce372e3a742f45d31447765c4004fbe5fbfdc1f5a32903ac87182c75e6abe021ab003c8af6e6cc33e0d01e'
11
+ end
12
+ # rubocop: enable Metrics/LineLength
13
+
14
+ RSpec.describe Prawn do
15
+ describe 'manual' do
16
+ # JRuby's zlib is a bit quirky. It sometimes produces different output to
17
+ # libzlib (used by MRI). It's still a proper deflate stream and can be
18
+ # decompressed just fine but for whatever reason compressin produses
19
+ # different output.
20
+ #
21
+ # See: https://github.com/jruby/jruby/issues/4244
22
+ it 'contains no unexpected changes' do
23
+ ENV['CI'] ||= 'true'
24
+
25
+ require File.expand_path(File.join(__dir__, %w[.. manual contents]))
26
+ s = prawn_manual_document.render
27
+
28
+ hash = Digest::SHA512.hexdigest(s)
29
+
30
+ expect(hash).to eq MANUAL_HASH
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,546 @@
1
+ require 'spec_helper'
2
+
3
+ describe Prawn::Document::BoundingBox do
4
+ let(:pdf) { create_pdf }
5
+ let(:x) { 100 }
6
+ let(:y) { 125 }
7
+ let(:width) { 50 }
8
+ let(:height) { 75 }
9
+ let(:box) do
10
+ described_class.new(
11
+ nil,
12
+ nil,
13
+ [x, y],
14
+ width: width,
15
+ height: height
16
+ )
17
+ end
18
+
19
+ it 'has an anchor at (x, y - height)' do
20
+ expect(box.anchor).to eq([x, y - height])
21
+ end
22
+
23
+ it 'has a left boundary of 0' do
24
+ expect(box.left).to eq(0)
25
+ end
26
+
27
+ it 'has a right boundary equal to the width' do
28
+ expect(box.right).to eq(width)
29
+ end
30
+
31
+ it 'has a top boundary of height' do
32
+ expect(box.top).to eq(height)
33
+ end
34
+
35
+ it 'has a bottom boundary of 0' do
36
+ expect(box.bottom).to eq(0)
37
+ end
38
+
39
+ it 'has a top-left of [0,height]' do
40
+ expect(box.top_left).to eq([0, height])
41
+ end
42
+
43
+ it 'has a top-right of [width,height]' do
44
+ expect(box.top_right).to eq([width, height])
45
+ end
46
+
47
+ it 'has a bottom-left of [0,0]' do
48
+ expect(box.bottom_left).to eq([0, 0])
49
+ end
50
+
51
+ it 'has a bottom-right of [width,0]' do
52
+ expect(box.bottom_right).to eq([width, 0])
53
+ end
54
+
55
+ it 'has an absolute left boundary of x' do
56
+ expect(box.absolute_left).to eq(x)
57
+ end
58
+
59
+ it 'has an absolute right boundary of x + width' do
60
+ expect(box.absolute_right).to eq(x + width)
61
+ end
62
+
63
+ it 'has an absolute top boundary of y' do
64
+ expect(box.absolute_top).to eq(y)
65
+ end
66
+
67
+ it 'has an absolute bottom boundary of y - height' do
68
+ expect(box.absolute_bottom).to eq(y - height)
69
+ end
70
+
71
+ it 'has an absolute bottom-left of [x,y-height]' do
72
+ expect(box.absolute_bottom_left).to eq([x, y - height])
73
+ end
74
+
75
+ it 'has an absolute bottom-right of [x+width,y-height]' do
76
+ expect(box.absolute_bottom_right).to eq([x + width, y - height])
77
+ end
78
+
79
+ it 'has an absolute top-left of [x,y]' do
80
+ expect(box.absolute_top_left).to eq([x, y])
81
+ end
82
+
83
+ it 'has an absolute top-right of [x+width,y]' do
84
+ expect(box.absolute_top_right).to eq([x + width, y])
85
+ end
86
+
87
+ it 'requires width to be set' do
88
+ expect do
89
+ described_class.new(nil, nil, [100, 100])
90
+ end.to raise_error(ArgumentError)
91
+ end
92
+
93
+ it 'raise_errors an ArgumentError if a block is not passed' do
94
+ pdf = Prawn::Document.new
95
+ expect do
96
+ pdf.bounding_box([0, 0], width: 200)
97
+ end.to raise_error(ArgumentError)
98
+ end
99
+
100
+ describe 'drawing' do
101
+ it 'does not stomp on the arguments to bounding_box' do
102
+ pdf = Prawn::Document.new
103
+ x = [100, 500]
104
+ pdf.bounding_box x, width: 100 do
105
+ pdf.text 'bork-bork-bork'
106
+ end
107
+ expect(x).to eq([100, 500])
108
+ end
109
+
110
+ it 'restores Document#bounds to the correct margin box on exit' do
111
+ pdf = Prawn::Document.new(margin: 200)
112
+
113
+ # add a multi-page bounding box
114
+ pdf.bounding_box([100, pdf.bounds.top], width: 400) do
115
+ pdf.text "The rain in spain falls mainly in the plains.\n" * 30
116
+ end
117
+
118
+ pdf.start_new_page(margin: 0)
119
+
120
+ x_min, y_min, x_max, y_max = pdf.page.dimensions
121
+
122
+ expect(pdf.bounds.absolute_top_left).to eq([x_min, y_max])
123
+ expect(pdf.bounds.absolute_bottom_right).to eq([x_max, y_min])
124
+ end
125
+
126
+ it 'restores the parent bounding box when calls are nested' do
127
+ pdf.bounding_box [100, 500], width: 300, height: 300 do
128
+ expect(pdf.bounds.absolute_top)
129
+ .to eq(500 + pdf.margin_box.absolute_bottom)
130
+ expect(pdf.bounds.absolute_left)
131
+ .to eq(100 + pdf.margin_box.absolute_left)
132
+
133
+ parent_box = pdf.bounds
134
+
135
+ pdf.bounding_box [50, 200], width: 100, height: 100 do
136
+ expect(pdf.bounds.absolute_top)
137
+ .to eq(200 + parent_box.absolute_bottom)
138
+ expect(pdf.bounds.absolute_left).to eq(50 + parent_box.absolute_left)
139
+ end
140
+
141
+ expect(pdf.bounds.absolute_top)
142
+ .to eq(500 + pdf.margin_box.absolute_bottom)
143
+ expect(pdf.bounds.absolute_left)
144
+ .to eq(100 + pdf.margin_box.absolute_left)
145
+ end
146
+ end
147
+
148
+ it 'calculates a height if none is specified' do
149
+ pdf.bounding_box([100, 500], width: 100) do
150
+ pdf.text 'The rain in Spain falls mainly on the plains.'
151
+ end
152
+
153
+ expect(pdf.y).to be_within(0.001).of(458.384)
154
+ end
155
+
156
+ it 'keeps track of the max height the box was stretched to' do
157
+ box = pdf.bounding_box(pdf.bounds.top_left, width: 100) do
158
+ pdf.move_down 100
159
+ pdf.move_up 15
160
+ end
161
+
162
+ expect(box.height).to eq(100)
163
+ end
164
+
165
+ it 'advances the y-position by bbox.height by default' do
166
+ orig_y = pdf.y
167
+ pdf.bounding_box [0, pdf.cursor], width: pdf.bounds.width, height: 30 do
168
+ pdf.text 'hello'
169
+ end
170
+ expect(pdf.y).to be_within(0.001).of(orig_y - 30)
171
+ end
172
+
173
+ it 'does not advance y-position if passed :hold_position => true' do
174
+ orig_y = pdf.y
175
+ pdf.bounding_box(
176
+ [0, pdf.cursor],
177
+ width: pdf.bounds.width,
178
+ hold_position: true
179
+ ) do
180
+ pdf.text 'hello'
181
+ end
182
+ # y only advances by height of one line ("hello")
183
+ expect(pdf.y).to be_within(0.001).of(orig_y - pdf.height_of('hello'))
184
+ end
185
+
186
+ it 'should not advance y-position of a stretchy bbox if it would stretch ' \
187
+ 'the bbox further' do
188
+ bottom = pdf.y = pdf.margin_box.absolute_bottom
189
+ pdf.bounding_box [0, pdf.margin_box.top], width: pdf.bounds.width do
190
+ pdf.y = bottom
191
+ pdf.text 'hello' # starts a new page
192
+ end
193
+ expect(pdf.page_count).to eq(2)
194
+
195
+ # Restoring the position (to the absolute bottom) would stretch the bbox
196
+ # to the bottom of the page, which we don't want. This should be
197
+ # equivalent to a bbox with :hold_position => true, where we only advance
198
+ # by the amount that was actually drawn.
199
+ expect(pdf.y).to be_within(0.001).of(
200
+ pdf.margin_box.absolute_top - pdf.height_of('hello')
201
+ )
202
+ end
203
+ end
204
+
205
+ describe 'Indentation' do
206
+ it 'temporarilies shift the x coordinate and width' do
207
+ pdf.bounding_box([100, 100], width: 200) do
208
+ pdf.indent(20) do
209
+ expect(pdf.bounds.absolute_left).to eq(120)
210
+ expect(pdf.bounds.width).to eq(180)
211
+ end
212
+ end
213
+ end
214
+
215
+ it 'restores the x coordinate and width after block exits' do
216
+ pdf.bounding_box([100, 100], width: 200) do
217
+ pdf.indent(20) do
218
+ # no-op
219
+ end
220
+ expect(pdf.bounds.absolute_left).to eq(100)
221
+ expect(pdf.bounds.width).to eq(200)
222
+ end
223
+ end
224
+
225
+ it 'restores the x coordinate and width on error' do
226
+ pdf.bounding_box([100, 100], width: 200) do
227
+ begin
228
+ pdf.indent(20) { raise }
229
+ rescue
230
+ expect(pdf.bounds.absolute_left).to eq(100)
231
+ expect(pdf.bounds.width).to eq(200)
232
+ end
233
+ end
234
+ end
235
+
236
+ it 'maintains left indentation across a page break' do
237
+ original_left = pdf.bounds.absolute_left
238
+
239
+ pdf.indent(20) do
240
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
241
+ pdf.start_new_page
242
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
243
+ end
244
+
245
+ expect(pdf.bounds.absolute_left).to eq(original_left)
246
+ end
247
+
248
+ it 'maintains right indentation across a page break' do
249
+ original_width = pdf.bounds.width
250
+
251
+ pdf.indent(0, 20) do
252
+ expect(pdf.bounds.width).to eq(original_width - 20)
253
+ pdf.start_new_page
254
+ expect(pdf.bounds.width).to eq(original_width - 20)
255
+ end
256
+
257
+ expect(pdf.bounds.width).to eq(original_width)
258
+ end
259
+
260
+ it 'optionally allows adjustment of the right bound as well' do
261
+ pdf.bounding_box([100, 100], width: 200) do
262
+ pdf.indent(20, 30) do
263
+ expect(pdf.bounds.absolute_left).to eq(120)
264
+ expect(pdf.bounds.width).to eq(150)
265
+ end
266
+ expect(pdf.bounds.absolute_left).to eq(100)
267
+ expect(pdf.bounds.width).to eq(200)
268
+ end
269
+ end
270
+
271
+ describe 'in a ColumnBox' do
272
+ it 'subtracts the given indentation from the available width' do
273
+ pdf.column_box(
274
+ [0, pdf.cursor],
275
+ width: pdf.bounds.width,
276
+ height: 200,
277
+ columns: 2,
278
+ spacer: 20
279
+ ) do
280
+ width = pdf.bounds.width
281
+ pdf.indent(20) do
282
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 20)
283
+ end
284
+ end
285
+ end
286
+
287
+ it 'subtracts right padding from the available width' do
288
+ pdf.column_box(
289
+ [0, pdf.cursor],
290
+ width: pdf.bounds.width,
291
+ height: 200,
292
+ columns: 2,
293
+ spacer: 20
294
+ ) do
295
+ width = pdf.bounds.width
296
+ pdf.indent(20, 30) do
297
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 50)
298
+ end
299
+ end
300
+ end
301
+
302
+ it 'maintains the same left indentation across column breaks' do
303
+ pdf.column_box(
304
+ [0, pdf.cursor],
305
+ width: pdf.bounds.width,
306
+ columns: 3,
307
+ spacer: 15
308
+ ) do
309
+ 3.times do |_column|
310
+ x = pdf.bounds.left_side
311
+ pdf.indent(20) do
312
+ expect(pdf.bounds.left_side).to eq(x + 20)
313
+ end
314
+ pdf.bounds.move_past_bottom
315
+ end
316
+ end
317
+ end
318
+
319
+ it 'does not change the right margin if only left indentation is '\
320
+ 'requested' do
321
+ pdf.column_box(
322
+ [0, pdf.cursor],
323
+ width: pdf.bounds.width,
324
+ columns: 3,
325
+ spacer: 15
326
+ ) do
327
+ 3.times do |_column|
328
+ x = pdf.bounds.right_side
329
+ pdf.indent(20) do
330
+ expect(pdf.bounds.right_side).to eq(x)
331
+ end
332
+ pdf.bounds.move_past_bottom
333
+ end
334
+ end
335
+ end
336
+
337
+ it 'maintains the same right indentation across columns' do
338
+ pdf.column_box(
339
+ [0, pdf.cursor],
340
+ width: pdf.bounds.width,
341
+ columns: 3,
342
+ spacer: 15
343
+ ) do
344
+ 3.times do |_column|
345
+ x = pdf.bounds.right_side
346
+ pdf.indent(20, 10) do
347
+ expect(pdf.bounds.right_side).to eq(x - 10)
348
+ end
349
+ pdf.bounds.move_past_bottom
350
+ end
351
+ end
352
+ end
353
+
354
+ it 'keeps the right indentation after nesting indents' do
355
+ pdf.column_box(
356
+ [0, pdf.cursor],
357
+ width: pdf.bounds.width,
358
+ columns: 3,
359
+ spacer: 15
360
+ ) do
361
+ 3.times do |_column|
362
+ # I am giving a right indent of 10...
363
+ pdf.indent(20, 10) do
364
+ x = pdf.bounds.right_side
365
+ # ...and no right indent here...
366
+ pdf.indent(20) do
367
+ # right indent is inherited from the parent!
368
+ expect(pdf.bounds.right_side).to eq(x)
369
+ end
370
+ end
371
+ pdf.bounds.move_past_bottom
372
+ end
373
+ end
374
+ end
375
+
376
+ it 'reverts the right indentation if negative indent is given in '\
377
+ 'nested indent' do
378
+ pdf.column_box(
379
+ [0, pdf.cursor],
380
+ width: pdf.bounds.width,
381
+ columns: 3,
382
+ spacer: 15
383
+ ) do
384
+ 3.times do |_column|
385
+ x = pdf.bounds.right_side
386
+ pdf.indent(20, 10) do
387
+ # requesting a negative right-indent of equivalent size...
388
+ pdf.indent(20, -10) do
389
+ # ...resets the right margin to that of the column!
390
+ expect(pdf.bounds.right_side).to eq(x)
391
+ end
392
+ end
393
+ pdf.bounds.move_past_bottom
394
+ end
395
+ end
396
+ end
397
+
398
+ it 'reduces the available column width by the sum of ' \
399
+ 'all nested indents' do
400
+ pdf.column_box(
401
+ [0, pdf.cursor],
402
+ width: pdf.bounds.width,
403
+ columns: 3,
404
+ spacer: 15
405
+ ) do
406
+ 3.times do |_column|
407
+ w = pdf.bounds.width
408
+ pdf.indent(20, 10) do
409
+ pdf.indent(20, 10) do
410
+ expect(pdf.bounds.width).to eq(w - 60)
411
+ end
412
+ end
413
+ pdf.bounds.move_past_bottom
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+
420
+ describe 'A canvas' do
421
+ it 'uses whatever the last set y position is' do
422
+ pdf.canvas do
423
+ pdf.bounding_box([100, 500], width: 200) { pdf.move_down 50 }
424
+ end
425
+ expect(pdf.y).to eq(450)
426
+ end
427
+
428
+ it 'restores the original ypos after execution', issue: 523 do
429
+ doc = Prawn::Document.new(skip_page_creation: true)
430
+ doc.start_new_page
431
+
432
+ original_ypos = doc.y
433
+
434
+ doc.canvas {}
435
+
436
+ expect(doc.y).to eq(original_ypos)
437
+ end
438
+ end
439
+
440
+ describe 'Deep-copying' do
441
+ it 'creates a new object that does not copy @document' do
442
+ Prawn::Document.new do |pdf|
443
+ orig = pdf.bounds
444
+ copy = orig.deep_copy
445
+
446
+ expect(copy).to_not eq(pdf.bounds)
447
+ expect(copy.document).to be_nil
448
+ end
449
+ end
450
+
451
+ it 'deep-copies parent bounds' do
452
+ Prawn::Document.new do |pdf|
453
+ outside = pdf.bounds
454
+ pdf.bounding_box [100, 100], width: 100 do
455
+ copy = pdf.bounds.deep_copy
456
+
457
+ # the parent bounds should have the same parameters
458
+ expect(copy.parent.width).to eq(outside.width)
459
+ expect(copy.parent.height).to eq(outside.height)
460
+
461
+ # but should not be the same object
462
+ expect(copy.parent).to_not eq(outside)
463
+ end
464
+ end
465
+ end
466
+ end
467
+
468
+ describe 'Prawn::Document#reference_bounds' do
469
+ it 'returns self for non-stretchy bounds' do
470
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
471
+ expect(pdf.reference_bounds).to eq(pdf.bounds)
472
+ end
473
+ end
474
+
475
+ it 'returns the parent bounds if in a stretchy box' do
476
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
477
+ correct_bounds = pdf.bounds
478
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
479
+ expect(pdf.reference_bounds).to eq(correct_bounds)
480
+ end
481
+ end
482
+ end
483
+
484
+ it 'finds the non-stretchy box through 2 levels' do
485
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
486
+ correct_bounds = pdf.bounds
487
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
488
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
489
+ expect(pdf.reference_bounds).to eq(correct_bounds)
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ it "returns the margin box if there's no explicit bbox" do
496
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
497
+
498
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
499
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
500
+ end
501
+ end
502
+
503
+ it "returns the canvas box if we're in a canvas" do
504
+ pdf.canvas do
505
+ canvas_box = pdf.bounds
506
+
507
+ expect(pdf.reference_bounds).to eq(canvas_box)
508
+
509
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
510
+ expect(pdf.reference_bounds).to eq(canvas_box)
511
+ end
512
+ end
513
+ end
514
+ end
515
+
516
+ describe '#move_past_bottom' do
517
+ it 'ordinarilies start a new page' do
518
+ pdf.bounds.move_past_bottom
519
+ pdf.text 'Foo'
520
+
521
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
522
+ expect(pages.size).to eq(2)
523
+ expect(pages[0][:strings]).to eq([])
524
+ expect(pages[1][:strings]).to eq(['Foo'])
525
+ end
526
+
527
+ it 'moves to the top of the next page if it exists already' do
528
+ # save away the y-position at the top of a page
529
+ top_y = pdf.y
530
+
531
+ # create a blank page but go to the page before it
532
+ pdf.start_new_page
533
+ pdf.go_to_page 1
534
+ pdf.text 'Foo'
535
+
536
+ pdf.bounds.move_past_bottom
537
+ expect(pdf.y).to be_within(0.001).of(top_y)
538
+ pdf.text 'Bar'
539
+
540
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
541
+ expect(pages.size).to eq(2)
542
+ expect(pages[0][:strings]).to eq(['Foo'])
543
+ expect(pages[1][:strings]).to eq(['Bar'])
544
+ end
545
+ end
546
+ end