prawn 2.0.2 → 2.3.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 (277) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +20 -23
  7. data/lib/prawn.rb +37 -49
  8. data/lib/prawn/document.rb +181 -133
  9. data/lib/prawn/document/bounding_box.rb +41 -29
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +18 -8
  12. data/lib/prawn/document/span.rb +21 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +115 -69
  16. data/lib/prawn/font_metric_cache.rb +14 -8
  17. data/lib/prawn/{font → fonts}/afm.rb +102 -68
  18. data/lib/prawn/{font → fonts}/dfont.rb +5 -11
  19. data/lib/prawn/fonts/otf.rb +11 -0
  20. data/lib/prawn/fonts/ttc.rb +36 -0
  21. data/lib/prawn/{font → fonts}/ttf.rb +87 -68
  22. data/lib/prawn/graphics.rb +120 -80
  23. data/lib/prawn/graphics/blend_mode.rb +65 -0
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +27 -25
  26. data/lib/prawn/graphics/dash.rb +23 -11
  27. data/lib/prawn/graphics/join_style.rb +9 -3
  28. data/lib/prawn/graphics/patterns.rb +197 -67
  29. data/lib/prawn/graphics/transformation.rb +17 -8
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +48 -47
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +39 -30
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +28 -22
  36. data/lib/prawn/images/png.rb +107 -66
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +97 -77
  40. data/lib/prawn/repeater.rb +14 -10
  41. data/lib/prawn/security.rb +81 -61
  42. data/lib/prawn/security/arcfour.rb +2 -2
  43. data/lib/prawn/soft_mask.rb +26 -26
  44. data/lib/prawn/stamp.rb +20 -13
  45. data/lib/prawn/text.rb +68 -52
  46. data/lib/prawn/text/box.rb +11 -8
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +78 -49
  49. data/lib/prawn/text/formatted/box.rb +134 -100
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +121 -63
  52. data/lib/prawn/text/formatted/parser.rb +139 -117
  53. data/lib/prawn/text/formatted/wrap.rb +43 -31
  54. data/lib/prawn/transformation_stack.rb +44 -0
  55. data/lib/prawn/utilities.rb +7 -22
  56. data/lib/prawn/version.rb +2 -2
  57. data/lib/prawn/view.rb +17 -7
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +31 -22
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +6 -7
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +22 -16
  66. data/manual/bounding_box/bounding_box.rb +29 -24
  67. data/manual/bounding_box/bounds.rb +11 -12
  68. data/manual/bounding_box/canvas.rb +4 -5
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +24 -17
  72. data/manual/bounding_box/russian_boxes.rb +14 -13
  73. data/manual/bounding_box/stretchy.rb +12 -13
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -28
  76. data/manual/document_and_page_options/background.rb +11 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +25 -20
  78. data/manual/document_and_page_options/metadata.rb +18 -16
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -12
  81. data/manual/document_and_page_options/print_scaling.rb +17 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +4 -5
  88. data/manual/graphics/fill_rules.rb +9 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -39
  91. data/manual/graphics/helper.rb +12 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +7 -8
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -7
  97. data/manual/graphics/scale.rb +14 -15
  98. data/manual/graphics/soft_masks.rb +4 -5
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +11 -12
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +9 -10
  103. data/manual/graphics/transparency.rb +7 -8
  104. data/manual/how_to_read_this_manual.rb +6 -6
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +9 -10
  108. data/manual/images/images.rb +28 -24
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +13 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +5 -6
  114. data/manual/layout/content.rb +7 -8
  115. data/manual/layout/layout.rb +18 -16
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +21 -17
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +25 -19
  124. data/manual/repeatable_content/repeater.rb +14 -15
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +9 -10
  127. data/manual/security/permissions.rb +19 -14
  128. data/manual/security/security.rb +19 -16
  129. data/manual/table.rb +3 -3
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -11
  132. data/manual/text/column_box.rb +9 -10
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +7 -8
  137. data/manual/text/formatted_callbacks.rb +25 -21
  138. data/manual/text/formatted_text.rb +33 -25
  139. data/manual/text/free_flowing_text.rb +20 -21
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +13 -14
  145. data/manual/text/positioned_text.rb +15 -16
  146. data/manual/text/registering_families.rb +20 -21
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +26 -19
  149. data/manual/text/rotation.rb +28 -23
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +57 -52
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +18 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +21 -19
  157. data/prawn.gemspec +45 -33
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +36 -0
  167. data/spec/prawn/document_spec.rb +802 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +542 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +837 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +224 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +412 -0
  180. data/spec/prawn/repeater_spec.rb +165 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +172 -0
  183. data/spec/prawn/text/box_spec.rb +1112 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +846 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +149 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -23
  198. metadata +145 -185
  199. metadata.gz.sig +4 -0
  200. data/data/images/16bit.alpha +0 -0
  201. data/data/images/16bit.color +0 -0
  202. data/data/images/16bit.png +0 -0
  203. data/data/images/arrow.png +0 -0
  204. data/data/images/arrow2.png +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/letterhead.jpg +0 -0
  213. data/data/images/license.md +0 -8
  214. data/data/images/page_white_text.alpha +0 -0
  215. data/data/images/page_white_text.color +0 -0
  216. data/data/images/page_white_text.png +0 -0
  217. data/data/images/pal_bk.png +0 -0
  218. data/data/images/pigs.jpg +0 -0
  219. data/data/images/prawn.png +0 -0
  220. data/data/images/ruport.png +0 -0
  221. data/data/images/ruport_data.dat +0 -0
  222. data/data/images/ruport_transparent.png +0 -0
  223. data/data/images/ruport_type0.png +0 -0
  224. data/data/images/stef.jpg +0 -0
  225. data/data/images/tru256.bmp +0 -0
  226. data/data/images/web-links.dat +0 -1
  227. data/data/images/web-links.png +0 -0
  228. data/data/pdfs/complex_template.pdf +0 -0
  229. data/data/pdfs/contains_ttf_font.pdf +0 -0
  230. data/data/pdfs/encrypted.pdf +0 -0
  231. data/data/pdfs/form.pdf +1 -819
  232. data/data/pdfs/hexagon.pdf +0 -61
  233. data/data/pdfs/indirect_reference.pdf +0 -86
  234. data/data/pdfs/multipage_template.pdf +0 -127
  235. data/data/pdfs/nested_pages.pdf +0 -118
  236. data/data/pdfs/page_without_mediabox.pdf +0 -193
  237. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  238. data/data/pdfs/two_hexagons.pdf +0 -90
  239. data/data/pdfs/version_1_6.pdf +0 -61
  240. data/data/shift_jis_text.txt +0 -1
  241. data/spec/acceptance/png.rb +0 -24
  242. data/spec/annotations_spec.rb +0 -67
  243. data/spec/bounding_box_spec.rb +0 -501
  244. data/spec/column_box_spec.rb +0 -59
  245. data/spec/destinations_spec.rb +0 -13
  246. data/spec/document_spec.rb +0 -742
  247. data/spec/extensions/mocha.rb +0 -45
  248. data/spec/font_metric_cache_spec.rb +0 -52
  249. data/spec/font_spec.rb +0 -475
  250. data/spec/formatted_text_arranger_spec.rb +0 -423
  251. data/spec/formatted_text_box_spec.rb +0 -716
  252. data/spec/formatted_text_fragment_spec.rb +0 -299
  253. data/spec/graphics_spec.rb +0 -666
  254. data/spec/grid_spec.rb +0 -95
  255. data/spec/image_handler_spec.rb +0 -53
  256. data/spec/images_spec.rb +0 -167
  257. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  258. data/spec/jpg_spec.rb +0 -23
  259. data/spec/line_wrap_spec.rb +0 -366
  260. data/spec/measurement_units_spec.rb +0 -22
  261. data/spec/outline_spec.rb +0 -409
  262. data/spec/png_spec.rb +0 -235
  263. data/spec/reference_spec.rb +0 -25
  264. data/spec/repeater_spec.rb +0 -154
  265. data/spec/security_spec.rb +0 -151
  266. data/spec/soft_mask_spec.rb +0 -78
  267. data/spec/span_spec.rb +0 -43
  268. data/spec/stamp_spec.rb +0 -179
  269. data/spec/stroke_styles_spec.rb +0 -208
  270. data/spec/text_at_spec.rb +0 -142
  271. data/spec/text_box_spec.rb +0 -1038
  272. data/spec/text_rendering_mode_spec.rb +0 -45
  273. data/spec/text_spacing_spec.rb +0 -93
  274. data/spec/text_spec.rb +0 -549
  275. data/spec/text_with_inline_formatting_spec.rb +0 -35
  276. data/spec/transparency_spec.rb +0 -91
  277. data/spec/view_spec.rb +0 -42
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "A column box" do
6
- it "has sensible left and right values" do
7
- create_pdf
8
- @pdf.column_box [0, @pdf.cursor], :width => @pdf.bounds.width, :height => 200, :columns => 3, :spacer => 25 do
9
- left = @pdf.bounds.left
10
- right = @pdf.bounds.right
11
-
12
- @pdf.bounds.move_past_bottom # next column
13
-
14
- expect(@pdf.bounds.left).to be > left
15
- expect(@pdf.bounds.left).to be > right
16
- expect(@pdf.bounds.right).to be > @pdf.bounds.left
17
- end
18
- end
19
-
20
- it "includes spacers between columns but not at the end" do
21
- create_pdf
22
- @pdf.column_box [0, @pdf.cursor], :width => 500, :height => 200, :columns => 3, :spacer => 25 do
23
- expect(@pdf.bounds.width).to eq(150) # (500 - (25 * 2)) / 3
24
-
25
- @pdf.bounds.move_past_bottom
26
- @pdf.bounds.move_past_bottom
27
-
28
- expect(@pdf.bounds.right).to eq(500)
29
- end
30
- end
31
-
32
- it "does not reset the top margin on a new page by default" do
33
- create_pdf
34
- page_top = @pdf.cursor
35
- @pdf.move_down 50
36
- init_column_top = @pdf.cursor
37
- @pdf.column_box [0, @pdf.cursor], :width => 500, :height => 200, :columns => 2 do
38
- @pdf.bounds.move_past_bottom
39
- @pdf.bounds.move_past_bottom
40
-
41
- expect(@pdf.bounds.absolute_top).to eq(init_column_top)
42
- expect(@pdf.bounds.absolute_top).not_to eq(page_top)
43
- end
44
- end
45
-
46
- it "does reset the top margin when reflow_margins is set" do
47
- create_pdf
48
- page_top = @pdf.cursor
49
- @pdf.move_down 50
50
- init_column_top = @pdf.cursor
51
- @pdf.column_box [0, @pdf.cursor], :width => 500, :reflow_margins => true, :height => 200, :columns => 2 do
52
- @pdf.bounds.move_past_bottom
53
- @pdf.bounds.move_past_bottom
54
-
55
- expect(@pdf.bounds.absolute_top).to eq(page_top)
56
- expect(@pdf.bounds.absolute_top).not_to eq(init_column_top)
57
- end
58
- end
59
- end
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "When creating destinations" do
6
- before(:each) { create_pdf }
7
-
8
- it "should add entry to Dests name tree" do
9
- expect(@pdf.dests.data.empty?).to eq(true)
10
- @pdf.add_dest "candy", "chocolate"
11
- expect(@pdf.dests.data.size).to eq(1)
12
- end
13
- end
@@ -1,742 +0,0 @@
1
- # encoding: utf-8
2
- require "tempfile"
3
-
4
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
5
-
6
- describe "Prawn::Document.new" do
7
- it "should not modify its argument" do
8
- options = { :page_layout => :landscape }
9
- Prawn::Document.new(options)
10
- expect(options).to eq(:page_layout => :landscape)
11
- end
12
- end
13
-
14
- describe "The cursor" do
15
- it "should == pdf.y - bounds.absolute_bottom" do
16
- pdf = Prawn::Document.new
17
- expect(pdf.cursor).to eq(pdf.bounds.top)
18
-
19
- pdf.y = 300
20
- expect(pdf.cursor).to eq(pdf.y - pdf.bounds.absolute_bottom)
21
- end
22
-
23
- it "should be able to move relative to the bottom margin" do
24
- pdf = Prawn::Document.new
25
- pdf.move_cursor_to(10)
26
-
27
- expect(pdf.cursor).to eq(10)
28
- expect(pdf.y).to eq(pdf.cursor + pdf.bounds.absolute_bottom)
29
- end
30
- end
31
-
32
- describe "when generating a document with a custom text formatter" do
33
- it "should use the provided text formatter" do
34
- class TestTextFormatter
35
- def self.format(string)
36
- [
37
- {
38
- text: string.gsub("Dr. Who?", "Just 'The Doctor'."),
39
- styles: [],
40
- color: nil,
41
- link: nil,
42
- anchor: nil,
43
- local: nil,
44
- font: nil,
45
- size: nil,
46
- character_spacing: nil
47
- }
48
- ]
49
- end
50
- end
51
- pdf = Prawn::Document.new text_formatter: TestTextFormatter
52
- pdf.text "Dr. Who?", inline_format: true
53
- text = PDF::Inspector::Text.analyze(pdf.render)
54
- expect(text.strings.first).to eq("Just 'The Doctor'.")
55
- end
56
- end
57
-
58
- describe "when generating a document from a subclass" do
59
- it "should be an instance of the subclass" do
60
- custom_document = Class.new(Prawn::Document)
61
- custom_document.generate(Tempfile.new("generate_test").path) do |e|
62
- expect(e.class).to eq(custom_document)
63
- expect(e).to be_a_kind_of(Prawn::Document)
64
- end
65
- end
66
-
67
- it "should retain any extensions found on Prawn::Document" do
68
- mod1 = Module.new { attr_reader :test_extensions1 }
69
- mod2 = Module.new { attr_reader :test_extensions2 }
70
-
71
- Prawn::Document.extensions << mod1 << mod2
72
-
73
- custom_document = Class.new(Prawn::Document)
74
- expect(custom_document.extensions).to eq([mod1, mod2])
75
-
76
- # remove the extensions we added to prawn document
77
- Prawn::Document.extensions.delete(mod1)
78
- Prawn::Document.extensions.delete(mod2)
79
-
80
- expect(Prawn::Document.new.respond_to?(:test_extensions1)).to be_false
81
- expect(Prawn::Document.new.respond_to?(:test_extensions2)).to be_false
82
-
83
- # verify these still exist on custom class
84
- expect(custom_document.extensions).to eq([mod1, mod2])
85
-
86
- expect(custom_document.new.respond_to?(:test_extensions1)).to be_true
87
- expect(custom_document.new.respond_to?(:test_extensions2)).to be_true
88
- end
89
- end
90
-
91
- describe "When creating multi-page documents" do
92
- before(:each) { create_pdf }
93
-
94
- it "should initialize with a single page" do
95
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
96
-
97
- expect(page_counter.pages.size).to eq(1)
98
- expect(@pdf.page_count).to eq(1)
99
- end
100
-
101
- it "should provide an accurate page_count" do
102
- 3.times { @pdf.start_new_page }
103
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
104
-
105
- expect(page_counter.pages.size).to eq(4)
106
- expect(@pdf.page_count).to eq(4)
107
- end
108
- end
109
-
110
- describe "When beginning each new page" do
111
- describe "Background image feature" do
112
- before(:each) do
113
- @filename = "#{Prawn::DATADIR}/images/pigs.jpg"
114
- @pdf = Prawn::Document.new(:background => @filename)
115
- end
116
- it "should place a background image if it is in options block" do
117
- output = @pdf.render
118
- images = PDF::Inspector::XObject.analyze(output)
119
- # there should be 2 images in the page resources
120
- expect(images.page_xobjects.first.size).to eq(1)
121
- end
122
- it "should place a background image if it is in options block" do
123
- expect(@pdf.instance_variable_defined?(:@background)).to eq(true)
124
- expect(@pdf.instance_variable_get(:@background)).to eq(@filename)
125
- end
126
- end
127
- end
128
-
129
- describe "Prawn::Document#float" do
130
- it "should restore the original y-position" do
131
- create_pdf
132
- orig_y = @pdf.y
133
- @pdf.float { @pdf.text "Foo" }
134
- expect(@pdf.y).to eq(orig_y)
135
- end
136
-
137
- it "should teleport across pages if necessary" do
138
- create_pdf
139
-
140
- @pdf.float do
141
- @pdf.text "Foo"
142
- @pdf.start_new_page
143
- @pdf.text "Bar"
144
- end
145
- @pdf.text "Baz"
146
-
147
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
148
- expect(pages.size).to eq(2)
149
- expect(pages[0][:strings]).to eq(["Foo", "Baz"])
150
- expect(pages[1][:strings]).to eq(["Bar"])
151
- end
152
- end
153
-
154
- describe "The page_number method" do
155
- it "should be 1 for a new document" do
156
- pdf = Prawn::Document.new
157
- expect(pdf.page_number).to eq(1)
158
- end
159
-
160
- it "should be 0 for documents with no pages" do
161
- pdf = Prawn::Document.new(:skip_page_creation => true)
162
- expect(pdf.page_number).to eq(0)
163
- end
164
-
165
- it "should be changed by go_to_page" do
166
- pdf = Prawn::Document.new
167
- 10.times { pdf.start_new_page }
168
- pdf.go_to_page 3
169
- expect(pdf.page_number).to eq(3)
170
- end
171
- end
172
-
173
- describe "on_page_create callback" do
174
- before do
175
- create_pdf
176
- end
177
-
178
- it "should be delegated from Document to renderer" do
179
- expect(@pdf.respond_to?(:on_page_create)).to be_true
180
- end
181
-
182
- it "should be invoked with document" do
183
- called_with = nil
184
-
185
- @pdf.renderer.on_page_create { |*args| called_with = args }
186
-
187
- @pdf.start_new_page
188
-
189
- expect(called_with).to eq([@pdf])
190
- end
191
-
192
- it "should be invoked for each new page" do
193
- trigger = mock
194
- trigger.expects(:fire).times(5)
195
-
196
- @pdf.renderer.on_page_create { trigger.fire }
197
-
198
- 5.times { @pdf.start_new_page }
199
- end
200
-
201
- it "should be replaceable" do
202
- trigger1 = mock
203
- trigger1.expects(:fire).times(1)
204
-
205
- trigger2 = mock
206
- trigger2.expects(:fire).times(1)
207
-
208
- @pdf.renderer.on_page_create { trigger1.fire }
209
-
210
- @pdf.start_new_page
211
-
212
- @pdf.renderer.on_page_create { trigger2.fire }
213
-
214
- @pdf.start_new_page
215
- end
216
-
217
- it "should be clearable by calling on_page_create without a block" do
218
- trigger = mock
219
- trigger.expects(:fire).times(1)
220
-
221
- @pdf.renderer.on_page_create { trigger.fire }
222
-
223
- @pdf.start_new_page
224
-
225
- @pdf.renderer.on_page_create
226
-
227
- @pdf.start_new_page
228
- end
229
- end
230
-
231
- describe "Document compression" do
232
- it "should not compress the page content stream if compression is disabled" do
233
- pdf = Prawn::Document.new(:compress => false)
234
- pdf.page.content.stream.stubs(:compress!).returns(true)
235
- pdf.page.content.stream.expects(:compress!).never
236
-
237
- pdf.text "Hi There" * 20
238
- pdf.render
239
- end
240
-
241
- it "should compress the page content stream if compression is enabled" do
242
- pdf = Prawn::Document.new(:compress => true)
243
- pdf.page.content.stream.stubs(:compress!).returns(true)
244
- pdf.page.content.stream.expects(:compress!).once
245
-
246
- pdf.text "Hi There" * 20
247
- pdf.render
248
- end
249
-
250
- it "should result in a smaller file size when compressed" do
251
- doc_uncompressed = Prawn::Document.new
252
- doc_compressed = Prawn::Document.new(:compress => true)
253
- [doc_compressed, doc_uncompressed].each do |pdf|
254
- pdf.font "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
255
- pdf.text "更可怕的是,同质化竞争对手可以按照URL中后面这个ID来遍历" * 10
256
- end
257
-
258
- expect(doc_compressed.render.length).to be < doc_uncompressed.render.length
259
- end
260
- end
261
-
262
- describe "Document metadata" do
263
- it "should output strings as UTF-16 with a byte order mark" do
264
- pdf = Prawn::Document.new(:info => { :Author => "Lóránt" })
265
- expect(pdf.state.store.info.object).to match(
266
- # UTF-16: BOM L ó r á n t
267
- %r{/Author\s*<feff004c00f3007200e1006e0074>}i
268
- )
269
- end
270
- end
271
-
272
- describe "When reopening pages" do
273
- it "should modify the content stream size" do
274
- @pdf = Prawn::Document.new do |pdf|
275
- pdf.text "Page 1"
276
- pdf.start_new_page
277
- pdf.text "Page 2"
278
- pdf.go_to_page 1
279
- pdf.text "More for page 1"
280
- end
281
-
282
- # Indirectly verify that the actual length does not match dictionary length.
283
- # If it isn't, a MalformedPDFError will be raised
284
- PDF::Inspector::Page.analyze(@pdf.render)
285
- end
286
-
287
- it "should insert pages after the current page when calling start_new_page" do
288
- pdf = Prawn::Document.new
289
- 3.times do |i|
290
- pdf.text "Old page #{i + 1}"
291
- pdf.start_new_page
292
- end
293
-
294
- pdf.go_to_page 1
295
- pdf.start_new_page
296
- pdf.text "New page 2"
297
-
298
- expect(pdf.page_number).to eq(2)
299
-
300
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
301
- expect(pages.size).to eq(5)
302
- expect(pages[1][:strings]).to eq(["New page 2"])
303
- expect(pages[2][:strings]).to eq(["Old page 2"])
304
- end
305
-
306
- it "should restore the layout of the page" do
307
- Prawn::Document.new do
308
- start_new_page :layout => :landscape
309
- lsize = [bounds.width, bounds.height]
310
-
311
- [bounds.width, bounds.height].should == lsize
312
- go_to_page 1
313
- [bounds.width, bounds.height].should == lsize.reverse
314
- end
315
- end
316
-
317
- it "should restore the margin box of the page" do
318
- Prawn::Document.new(:margin => [100, 100]) do
319
- page1_bounds = bounds
320
-
321
- start_new_page(:margin => [200, 200])
322
-
323
- [bounds.width, bounds.height].should == [page1_bounds.width - 200,
324
- page1_bounds.height - 200]
325
-
326
- go_to_page(1)
327
-
328
- bounds.width.should == page1_bounds.width
329
- bounds.height.should == page1_bounds.height
330
- end
331
- end
332
- end
333
-
334
- describe "When setting page size" do
335
- it "should default to LETTER" do
336
- @pdf = Prawn::Document.new
337
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
338
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES["LETTER"])
339
- end
340
-
341
- (PDF::Core::PageGeometry::SIZES.keys - ["LETTER"]).each do |k|
342
- it "should provide #{k} geometry" do
343
- @pdf = Prawn::Document.new(:page_size => k)
344
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
345
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES[k])
346
- end
347
- end
348
-
349
- it "should allow custom page size" do
350
- @pdf = Prawn::Document.new(:page_size => [1920, 1080])
351
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
352
- expect(pages.first[:size]).to eq([1920, 1080])
353
- end
354
-
355
- it "should retain page size by default when starting a new page" do
356
- @pdf = Prawn::Document.new(:page_size => "LEGAL")
357
- @pdf.start_new_page
358
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
359
- pages.each do |page|
360
- expect(page[:size]).to eq(PDF::Core::PageGeometry::SIZES["LEGAL"])
361
- end
362
- end
363
- end
364
-
365
- describe "When setting page layout" do
366
- it "should reverse coordinates for landscape" do
367
- @pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
368
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
369
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES["A4"].reverse)
370
- end
371
-
372
- it "should retain page layout by default when starting a new page" do
373
- @pdf = Prawn::Document.new(:page_layout => :landscape)
374
- @pdf.start_new_page(:trace => true)
375
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
376
- pages.each do |page|
377
- expect(page[:size]).to eq(PDF::Core::PageGeometry::SIZES["LETTER"].reverse)
378
- end
379
- end
380
-
381
- it "should swap the bounds when starting a new page with different layout" do
382
- @pdf = Prawn::Document.new
383
- size = [@pdf.bounds.width, @pdf.bounds.height]
384
- @pdf.start_new_page(:layout => :landscape)
385
- expect([@pdf.bounds.width, @pdf.bounds.height]).to eq(size.reverse)
386
- end
387
- end
388
-
389
- describe "The mask() feature" do
390
- it "should allow transactional restoration of attributes" do
391
- @pdf = Prawn::Document.new
392
- y, line_width = @pdf.y, @pdf.line_width
393
- @pdf.mask(:y, :line_width) do
394
- @pdf.y = y + 1
395
- @pdf.line_width = line_width + 1
396
- expect(@pdf.y).not_to eq(y)
397
- expect(@pdf.line_width).not_to eq(line_width)
398
- end
399
- expect(@pdf.y).to eq(y)
400
- expect(@pdf.line_width).to eq(line_width)
401
- end
402
- end
403
-
404
- describe "The group() feature" do
405
- xit "should return a true value if the content fits on one page" do
406
- pdf = Prawn::Document.new do
407
- val = group {
408
- text "Hello"
409
- text "World"
410
- }
411
- expect(!!val).to eq(true)
412
- end
413
- end
414
-
415
- xit "should group a simple block on a single page" do
416
- pdf = Prawn::Document.new do
417
- self.y = 50
418
- val = group do
419
- text "Hello"
420
- text "World"
421
- end
422
-
423
- # group should return a false value since a new page was started
424
- expect(!!val).to eq(false)
425
- end
426
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
427
- expect(pages.size).to eq(2)
428
- expect(pages[0][:strings]).to eq([])
429
- expect(pages[1][:strings]).to eq(["Hello", "World"])
430
- end
431
-
432
- xit "should raise_error CannotGroup if the content is too tall" do
433
- expect {
434
- Prawn::Document.new do
435
- group do
436
- 100.times { text "Too long" }
437
- end
438
- end.render
439
- }.to raise_error(Prawn::Errors::CannotGroup)
440
- end
441
-
442
- xit "should group within individual column boxes" do
443
- pdf = Prawn::Document.new do
444
- # Set up columns with grouped blocks of 0..49. 0 to 49 is slightly short
445
- # of the height of one page / column, so each column should get its own
446
- # group (every column should start with zero).
447
- column_box([0, bounds.top], :width => bounds.width, :columns => 7) do
448
- 10.times do
449
- group { 50.times { |i| text(i.to_s) } }
450
- end
451
- end
452
- end
453
-
454
- # Second page should start with a 0 because it's a new group.
455
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
456
- expect(pages.size).to eq(2)
457
- expect(pages[1][:strings].first).to eq('0')
458
- end
459
- end
460
-
461
- describe "The render() feature" do
462
- it "should return a 8 bit encoded string on a m17n aware VM" do
463
- @pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
464
- @pdf.line [100, 100], [200, 200]
465
- str = @pdf.render
466
- expect(str.encoding.to_s).to eq("ASCII-8BIT")
467
- end
468
-
469
- it "should trigger before_render callbacks just before rendering" do
470
- pdf = Prawn::Document.new
471
-
472
- seq = sequence("callback_order")
473
-
474
- # Verify the order: finalize -> fire callbacks -> render body
475
- pdf.renderer.expects(:finalize_all_page_contents).in_sequence(seq)
476
- trigger = mock
477
- trigger.expects(:fire).in_sequence(seq)
478
-
479
- # Store away the render_body method to be called below
480
- render_body = pdf.renderer.method(:render_body)
481
- pdf.renderer.expects(:render_body).in_sequence(seq)
482
-
483
- pdf.renderer.before_render{ trigger.fire }
484
-
485
- # Render the body to set up object offsets
486
- render_body.call(StringIO.new)
487
- pdf.render
488
- end
489
-
490
- it "should be idempotent" do
491
- pdf = Prawn::Document.new
492
-
493
- contents = pdf.render
494
- contents2 = pdf.render
495
- expect(contents2).to eq(contents)
496
- end
497
- end
498
-
499
- describe "PDF file versions" do
500
- it "should default to 1.3" do
501
- @pdf = Prawn::Document.new
502
- str = @pdf.render
503
- expect(str[0, 8]).to eq("%PDF-1.3")
504
- end
505
-
506
- it "should allow the default to be changed" do
507
- @pdf = Prawn::Document.new
508
- @pdf.renderer.min_version(1.4)
509
- str = @pdf.render
510
- expect(str[0, 8]).to eq("%PDF-1.4")
511
- end
512
- end
513
-
514
- describe "Documents that use go_to_page" do
515
- it "should have 2 pages after calling start_new_page and go_to_page" do
516
- @pdf = Prawn::Document.new
517
- @pdf.text "James"
518
- @pdf.start_new_page
519
- @pdf.text "Anthony"
520
- @pdf.go_to_page(1)
521
- @pdf.text "Healy"
522
-
523
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
524
- expect(page_counter.pages.size).to eq(2)
525
- end
526
-
527
- it "should correctly add text to pages" do
528
- @pdf = Prawn::Document.new
529
- @pdf.text "James"
530
- @pdf.start_new_page
531
- @pdf.text "Anthony"
532
- @pdf.go_to_page(1)
533
- @pdf.text "Healy"
534
-
535
- text = PDF::Inspector::Text.analyze(@pdf.render)
536
-
537
- expect(text.strings.size).to eq(3)
538
- expect(text.strings.include?("James")).to eq(true)
539
- expect(text.strings.include?("Anthony")).to eq(true)
540
- expect(text.strings.include?("Healy")).to eq(true)
541
- end
542
- end
543
-
544
- describe "content stream characteristics" do
545
- it "should have 1 single content stream for a single page PDF" do
546
- @pdf = Prawn::Document.new
547
- @pdf.text "James"
548
- output = StringIO.new(@pdf.render)
549
- hash = PDF::Reader::ObjectHash.new(output)
550
-
551
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
552
-
553
- expect(streams.size).to eq(1)
554
- end
555
-
556
- it "should have 1 single content stream for a single page PDF, even if go_to_page is used" do
557
- @pdf = Prawn::Document.new
558
- @pdf.text "James"
559
- @pdf.go_to_page(1)
560
- @pdf.text "Healy"
561
- output = StringIO.new(@pdf.render)
562
- hash = PDF::Reader::ObjectHash.new(output)
563
-
564
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
565
-
566
- expect(streams.size).to eq(1)
567
- end
568
- end
569
-
570
- describe "The number_pages method" do
571
- before do
572
- @pdf = Prawn::Document.new(:skip_page_creation => true)
573
- end
574
-
575
- it "replaces the '<page>' string with the proper page number" do
576
- @pdf.start_new_page
577
- @pdf.expects(:text_box).with("1, test", :height => 50)
578
- @pdf.number_pages "<page>, test", :page_filter => :all
579
- end
580
-
581
- it "replaces the '<total>' string with the total page count" do
582
- @pdf.start_new_page
583
- @pdf.expects(:text_box).with("test, 1", :height => 50)
584
- @pdf.number_pages "test, <total>", :page_filter => :all
585
- end
586
-
587
- it "must print each page if given the :all page_filter" do
588
- 10.times { @pdf.start_new_page }
589
- @pdf.expects(:text_box).times(10)
590
- @pdf.number_pages "test", :page_filter => :all
591
- end
592
-
593
- it "must print each page if no :page_filter is specified" do
594
- 10.times { @pdf.start_new_page }
595
- @pdf.expects(:text_box).times(10)
596
- @pdf.number_pages "test"
597
- end
598
-
599
- it "must not print the page number if given a nil filter" do
600
- 10.times { @pdf.start_new_page }
601
- @pdf.expects(:text_box).never
602
- @pdf.number_pages "test", :page_filter => nil
603
- end
604
-
605
- context "start_count_at option" do
606
- [1, 2].each do |startat|
607
- context "equal to #{startat}" do
608
- it "increments the pages" do
609
- 2.times { @pdf.start_new_page }
610
- options = { :page_filter => :all, :start_count_at => startat }
611
- @pdf.expects(:text_box).with("#{startat} 2", :height => 50)
612
- @pdf.expects(:text_box).with("#{startat + 1} 2", :height => 50)
613
- @pdf.number_pages "<page> <total>", options
614
- end
615
- end
616
- end
617
-
618
- [0, nil].each do |val|
619
- context "equal to #{val}" do
620
- it "defaults to start at page 1" do
621
- 3.times { @pdf.start_new_page }
622
- options = { :page_filter => :all, :start_count_at => val }
623
- @pdf.expects(:text_box).with("1 3", :height => 50)
624
- @pdf.expects(:text_box).with("2 3", :height => 50)
625
- @pdf.expects(:text_box).with("3 3", :height => 50)
626
- @pdf.number_pages "<page> <total>", options
627
- end
628
- end
629
- end
630
- end
631
-
632
- context "total_pages option" do
633
- it "allows the total pages count to be overridden" do
634
- 2.times { @pdf.start_new_page }
635
- @pdf.expects(:text_box).with("1 10", :height => 50)
636
- @pdf.expects(:text_box).with("2 10", :height => 50)
637
- @pdf.number_pages "<page> <total>", :page_filter => :all, :total_pages => 10
638
- end
639
- end
640
-
641
- context "special page filter" do
642
- context "such as :odd" do
643
- it "increments the pages" do
644
- 3.times { @pdf.start_new_page }
645
- @pdf.expects(:text_box).with("1 3", :height => 50)
646
- @pdf.expects(:text_box).with("3 3", :height => 50)
647
- @pdf.expects(:text_box).with("2 3", :height => 50).never
648
- @pdf.number_pages "<page> <total>", :page_filter => :odd
649
- end
650
- end
651
- context "missing" do
652
- it "does not print any page numbers" do
653
- 3.times { @pdf.start_new_page }
654
- @pdf.expects(:text_box).never
655
- @pdf.number_pages "<page> <total>", :page_filter => nil
656
- end
657
- end
658
- end
659
-
660
- context "given both a special page filter and a start_count_at parameter" do
661
- context "such as :odd and 7" do
662
- it "increments the pages" do
663
- 3.times { @pdf.start_new_page }
664
- @pdf.expects(:text_box).with("1 3", :height => 50).never
665
- @pdf.expects(:text_box).with("5 3", :height => 50) # page 1
666
- @pdf.expects(:text_box).with("6 3", :height => 50).never # page 2
667
- @pdf.expects(:text_box).with("7 3", :height => 50) # page 3
668
- @pdf.number_pages "<page> <total>", :page_filter => :odd, :start_count_at => 5
669
- end
670
- end
671
- context "some crazy proc and 2" do
672
- it "increments the pages" do
673
- 6.times { @pdf.start_new_page }
674
- options = { :page_filter => lambda { |p| p != 2 && p != 5 }, :start_count_at => 4 }
675
- @pdf.expects(:text_box).with("4 6", :height => 50) # page 1
676
- @pdf.expects(:text_box).with("5 6", :height => 50).never # page 2
677
- @pdf.expects(:text_box).with("6 6", :height => 50) # page 3
678
- @pdf.expects(:text_box).with("7 6", :height => 50) # page 4
679
- @pdf.expects(:text_box).with("8 6", :height => 50).never # page 5
680
- @pdf.expects(:text_box).with("9 6", :height => 50) # page 6
681
- @pdf.number_pages "<page> <total>", options
682
- end
683
- end
684
- end
685
-
686
- context "height option" do
687
- before do
688
- @pdf.start_new_page
689
- end
690
-
691
- it "with 10 height" do
692
- @pdf.expects(:text_box).with("1 1", :height => 10)
693
- @pdf.number_pages "<page> <total>", :height => 10
694
- end
695
-
696
- it "with nil height" do
697
- @pdf.expects(:text_box).with("1 1", :height => nil)
698
- @pdf.number_pages "<page> <total>", :height => nil
699
- end
700
-
701
- it "with no height" do
702
- @pdf.expects(:text_box).with("1 1", :height => 50)
703
- @pdf.number_pages "<page> <total>"
704
- end
705
- end
706
- end
707
-
708
- describe "The page_match? method" do
709
- before do
710
- @pdf = Prawn::Document.new(:skip_page_creation => true)
711
- 10.times { @pdf.start_new_page }
712
- end
713
-
714
- it "returns nil given no filter" do
715
- expect(@pdf.page_match?(:nil, 1)).to be_false
716
- end
717
-
718
- it "must provide an :all filter" do
719
- expect((1..@pdf.page_count).all? { |i| @pdf.page_match?(:all, i) }).to be_true
720
- end
721
-
722
- it "must provide an :odd filter" do
723
- odd, even = (1..@pdf.page_count).partition(&:odd?)
724
- expect(odd.all? { |i| @pdf.page_match?(:odd, i) }).to be_true
725
- expect(even.any? { |i| @pdf.page_match?(:odd, i) }).to be_false
726
- end
727
-
728
- it "must be able to filter by an array of page numbers" do
729
- fltr = [1, 2, 7]
730
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([1, 2, 7])
731
- end
732
-
733
- it "must be able to filter by a range of page numbers" do
734
- fltr = 2..4
735
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([2, 3, 4])
736
- end
737
-
738
- it "must be able to filter by an arbitrary proc" do
739
- fltr = lambda { |x| x == 1 or x % 3 == 0 }
740
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([1, 3, 6, 9])
741
- end
742
- end