prawn 0.11.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (353) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -2
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +1 -1
  8. data/Rakefile +29 -38
  9. data/data/images/16bit.alpha +0 -0
  10. data/data/images/16bit.color +0 -0
  11. data/data/images/dice.alpha +0 -0
  12. data/data/images/dice.color +0 -0
  13. data/data/images/indexed_color.dat +0 -0
  14. data/data/images/indexed_color.png +0 -0
  15. data/data/images/page_white_text.alpha +0 -0
  16. data/data/images/page_white_text.color +0 -0
  17. data/data/pdfs/nested_pages.pdf +13 -13
  18. data/lib/prawn/document/bounding_box.rb +87 -12
  19. data/lib/prawn/document/column_box.rb +57 -28
  20. data/lib/prawn/document/graphics_state.rb +11 -74
  21. data/lib/prawn/document/internals.rb +25 -23
  22. data/lib/prawn/document/snapshot.rb +11 -8
  23. data/lib/prawn/document/span.rb +12 -10
  24. data/lib/prawn/document.rb +250 -194
  25. data/lib/prawn/encoding.rb +9 -10
  26. data/lib/prawn/errors.rb +18 -29
  27. data/lib/prawn/font/afm.rb +52 -41
  28. data/lib/prawn/font/dfont.rb +4 -3
  29. data/lib/prawn/font/ttf.rb +44 -48
  30. data/lib/prawn/font.rb +138 -88
  31. data/lib/prawn/font_metric_cache.rb +47 -0
  32. data/lib/prawn/graphics/cap_style.rb +4 -3
  33. data/lib/prawn/graphics/color.rb +13 -5
  34. data/lib/prawn/graphics/dash.rb +53 -31
  35. data/lib/prawn/graphics/join_style.rb +9 -7
  36. data/lib/prawn/graphics/patterns.rb +138 -0
  37. data/lib/prawn/graphics/transformation.rb +10 -9
  38. data/lib/prawn/graphics/transparency.rb +3 -1
  39. data/lib/prawn/graphics.rb +316 -61
  40. data/lib/prawn/image_handler.rb +36 -0
  41. data/lib/prawn/images/image.rb +49 -0
  42. data/lib/prawn/images/jpg.rb +21 -15
  43. data/lib/prawn/images/png.rb +62 -119
  44. data/lib/prawn/images.rb +89 -108
  45. data/lib/prawn/layout/grid.rb +66 -54
  46. data/lib/prawn/layout.rb +10 -15
  47. data/lib/prawn/measurement_extensions.rb +10 -6
  48. data/lib/prawn/measurements.rb +27 -21
  49. data/lib/prawn/outline.rb +6 -308
  50. data/lib/prawn/repeater.rb +11 -9
  51. data/lib/prawn/security/arcfour.rb +1 -0
  52. data/lib/prawn/security.rb +55 -33
  53. data/lib/prawn/soft_mask.rb +96 -0
  54. data/lib/prawn/stamp.rb +5 -3
  55. data/lib/prawn/table/cell/image.rb +69 -0
  56. data/lib/prawn/table/cell/in_table.rb +4 -2
  57. data/lib/prawn/table/cell/span_dummy.rb +93 -0
  58. data/lib/prawn/table/cell/subtable.rb +2 -2
  59. data/lib/prawn/table/cell/text.rb +44 -26
  60. data/lib/prawn/table/cell.rb +302 -50
  61. data/lib/prawn/table/cells.rb +147 -49
  62. data/lib/prawn/table/column_width_calculator.rb +61 -0
  63. data/lib/prawn/table.rb +297 -118
  64. data/lib/prawn/text/box.rb +21 -5
  65. data/lib/prawn/text/formatted/arranger.rb +290 -0
  66. data/lib/prawn/text/formatted/box.rb +103 -59
  67. data/lib/prawn/text/formatted/fragment.rb +34 -23
  68. data/lib/prawn/text/formatted/line_wrap.rb +266 -0
  69. data/lib/prawn/text/formatted/parser.rb +15 -5
  70. data/lib/prawn/text/formatted/wrap.rb +150 -0
  71. data/lib/prawn/text/formatted.rb +5 -4
  72. data/lib/prawn/text.rb +38 -24
  73. data/lib/prawn/utilities.rb +46 -0
  74. data/lib/prawn.rb +85 -20
  75. data/manual/basic_concepts/adding_pages.rb +27 -0
  76. data/manual/basic_concepts/basic_concepts.rb +34 -0
  77. data/manual/basic_concepts/creation.rb +39 -0
  78. data/manual/basic_concepts/cursor.rb +33 -0
  79. data/manual/basic_concepts/measurement.rb +25 -0
  80. data/manual/basic_concepts/origin.rb +38 -0
  81. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  82. data/manual/bounding_box/bounding_box.rb +39 -0
  83. data/manual/bounding_box/bounds.rb +49 -0
  84. data/manual/bounding_box/canvas.rb +24 -0
  85. data/manual/bounding_box/creation.rb +23 -0
  86. data/manual/bounding_box/indentation.rb +46 -0
  87. data/manual/bounding_box/nesting.rb +45 -0
  88. data/manual/bounding_box/russian_boxes.rb +40 -0
  89. data/manual/bounding_box/stretchy.rb +31 -0
  90. data/manual/document_and_page_options/background.rb +27 -0
  91. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  92. data/manual/document_and_page_options/metadata.rb +23 -0
  93. data/manual/document_and_page_options/page_margins.rb +38 -0
  94. data/manual/document_and_page_options/page_size.rb +34 -0
  95. data/manual/document_and_page_options/print_scaling.rb +20 -0
  96. data/manual/example_file.rb +111 -0
  97. data/manual/example_helper.rb +411 -0
  98. data/manual/example_package.rb +53 -0
  99. data/manual/example_section.rb +46 -0
  100. data/manual/graphics/circle_and_ellipse.rb +22 -0
  101. data/manual/graphics/color.rb +24 -0
  102. data/manual/graphics/common_lines.rb +30 -0
  103. data/manual/graphics/fill_and_stroke.rb +42 -0
  104. data/manual/graphics/fill_rules.rb +37 -0
  105. data/manual/graphics/gradients.rb +37 -0
  106. data/manual/graphics/graphics.rb +58 -0
  107. data/manual/graphics/helper.rb +24 -0
  108. data/manual/graphics/line_width.rb +35 -0
  109. data/manual/graphics/lines_and_curves.rb +41 -0
  110. data/manual/graphics/polygon.rb +29 -0
  111. data/manual/graphics/rectangle.rb +21 -0
  112. data/manual/graphics/rotate.rb +28 -0
  113. data/manual/graphics/scale.rb +41 -0
  114. data/manual/graphics/soft_masks.rb +46 -0
  115. data/manual/graphics/stroke_cap.rb +31 -0
  116. data/manual/graphics/stroke_dash.rb +48 -0
  117. data/manual/graphics/stroke_join.rb +30 -0
  118. data/manual/graphics/translate.rb +29 -0
  119. data/manual/graphics/transparency.rb +35 -0
  120. data/manual/images/absolute_position.rb +23 -0
  121. data/manual/images/fit.rb +21 -0
  122. data/manual/images/horizontal.rb +25 -0
  123. data/manual/images/images.rb +40 -0
  124. data/manual/images/plain_image.rb +18 -0
  125. data/manual/images/scale.rb +22 -0
  126. data/manual/images/vertical.rb +28 -0
  127. data/manual/images/width_and_height.rb +25 -0
  128. data/manual/layout/boxes.rb +27 -0
  129. data/manual/layout/content.rb +25 -0
  130. data/manual/layout/layout.rb +28 -0
  131. data/manual/layout/simple_grid.rb +23 -0
  132. data/manual/manual/cover.rb +36 -0
  133. data/manual/manual/foreword.rb +85 -0
  134. data/manual/manual/how_to_read_this_manual.rb +41 -0
  135. data/manual/manual/manual.rb +34 -0
  136. data/manual/outline/add_subsection_to.rb +61 -0
  137. data/manual/outline/insert_section_after.rb +47 -0
  138. data/manual/outline/outline.rb +32 -0
  139. data/manual/outline/sections_and_pages.rb +67 -0
  140. data/manual/repeatable_content/page_numbering.rb +54 -0
  141. data/manual/repeatable_content/repeatable_content.rb +31 -0
  142. data/manual/repeatable_content/repeater.rb +55 -0
  143. data/manual/repeatable_content/stamp.rb +41 -0
  144. data/manual/security/encryption.rb +31 -0
  145. data/manual/security/permissions.rb +38 -0
  146. data/manual/security/security.rb +28 -0
  147. data/manual/syntax_highlight.rb +52 -0
  148. data/manual/table/basic_block.rb +53 -0
  149. data/manual/table/before_rendering_page.rb +26 -0
  150. data/manual/table/cell_border_lines.rb +24 -0
  151. data/manual/table/cell_borders_and_bg.rb +31 -0
  152. data/manual/table/cell_dimensions.rb +30 -0
  153. data/manual/table/cell_text.rb +38 -0
  154. data/manual/table/column_widths.rb +30 -0
  155. data/manual/table/content_and_subtables.rb +39 -0
  156. data/manual/table/creation.rb +27 -0
  157. data/manual/table/filtering.rb +36 -0
  158. data/manual/table/flow_and_header.rb +17 -0
  159. data/manual/table/image_cells.rb +33 -0
  160. data/manual/table/position.rb +29 -0
  161. data/manual/table/row_colors.rb +20 -0
  162. data/manual/table/span.rb +30 -0
  163. data/manual/table/style.rb +22 -0
  164. data/manual/table/table.rb +52 -0
  165. data/manual/table/width.rb +27 -0
  166. data/manual/text/alignment.rb +44 -0
  167. data/manual/text/color.rb +24 -0
  168. data/manual/text/column_box.rb +32 -0
  169. data/manual/text/fallback_fonts.rb +37 -0
  170. data/manual/text/font.rb +41 -0
  171. data/manual/text/font_size.rb +45 -0
  172. data/manual/text/font_style.rb +23 -0
  173. data/manual/text/formatted_callbacks.rb +60 -0
  174. data/manual/text/formatted_text.rb +54 -0
  175. data/manual/text/free_flowing_text.rb +51 -0
  176. data/manual/text/group.rb +31 -0
  177. data/manual/text/inline.rb +43 -0
  178. data/manual/text/kerning_and_character_spacing.rb +39 -0
  179. data/manual/text/leading.rb +25 -0
  180. data/manual/text/line_wrapping.rb +41 -0
  181. data/manual/text/paragraph_indentation.rb +26 -0
  182. data/manual/text/positioned_text.rb +38 -0
  183. data/manual/text/registering_families.rb +48 -0
  184. data/manual/text/rendering_and_color.rb +37 -0
  185. data/manual/text/right_to_left_text.rb +43 -0
  186. data/manual/text/rotation.rb +43 -0
  187. data/manual/text/single_usage.rb +37 -0
  188. data/manual/text/text.rb +75 -0
  189. data/manual/text/text_box_excess.rb +32 -0
  190. data/manual/text/text_box_extensions.rb +45 -0
  191. data/manual/text/text_box_overflow.rb +44 -0
  192. data/manual/text/utf8.rb +28 -0
  193. data/{examples/m17n → manual/text}/win_ansi_charset.rb +14 -10
  194. data/prawn.gemspec +27 -17
  195. data/spec/acceptance/png.rb +23 -0
  196. data/spec/annotations_spec.rb +16 -32
  197. data/spec/bounding_box_spec.rb +284 -2
  198. data/spec/cell_spec.rb +169 -38
  199. data/spec/column_box_spec.rb +65 -0
  200. data/spec/data/curves.pdf +66 -0
  201. data/spec/destinations_spec.rb +5 -5
  202. data/spec/document_spec.rb +212 -113
  203. data/spec/extensions/encoding_helpers.rb +9 -0
  204. data/spec/extensions/mocha.rb +2 -3
  205. data/spec/font_metric_cache_spec.rb +52 -0
  206. data/spec/font_spec.rb +205 -95
  207. data/spec/formatted_text_arranger_spec.rb +43 -43
  208. data/spec/formatted_text_box_spec.rb +63 -24
  209. data/spec/formatted_text_fragment_spec.rb +8 -8
  210. data/spec/graphics_spec.rb +175 -68
  211. data/spec/grid_spec.rb +26 -15
  212. data/spec/image_handler_spec.rb +54 -0
  213. data/spec/images_spec.rb +58 -30
  214. data/spec/inline_formatted_text_parser_spec.rb +73 -19
  215. data/spec/jpg_spec.rb +4 -4
  216. data/spec/line_wrap_spec.rb +28 -28
  217. data/spec/measurement_units_spec.rb +6 -6
  218. data/spec/object_store_spec.rb +17 -106
  219. data/spec/outline_spec.rb +103 -63
  220. data/spec/png_spec.rb +25 -25
  221. data/spec/reference_spec.rb +8 -65
  222. data/spec/repeater_spec.rb +25 -11
  223. data/spec/security_spec.rb +44 -12
  224. data/spec/snapshot_spec.rb +38 -6
  225. data/spec/soft_mask_spec.rb +117 -0
  226. data/spec/span_spec.rb +10 -15
  227. data/spec/spec_helper.rb +32 -8
  228. data/spec/stamp_spec.rb +29 -30
  229. data/spec/stroke_styles_spec.rb +36 -18
  230. data/spec/table/span_dummy_spec.rb +17 -0
  231. data/spec/table_spec.rb +850 -104
  232. data/spec/text_at_spec.rb +19 -33
  233. data/spec/text_box_spec.rb +117 -64
  234. data/spec/text_rendering_mode_spec.rb +5 -5
  235. data/spec/text_spacing_spec.rb +20 -2
  236. data/spec/text_spec.rb +111 -59
  237. data/spec/transparency_spec.rb +5 -5
  238. metadata +477 -328
  239. data/HACKING +0 -50
  240. data/README +0 -141
  241. data/data/fonts/Action Man.dfont +0 -0
  242. data/data/fonts/Activa.ttf +0 -0
  243. data/data/fonts/Chalkboard.ttf +0 -0
  244. data/data/fonts/DejaVuSans.ttf +0 -0
  245. data/data/fonts/Dustismo_Roman.ttf +0 -0
  246. data/data/fonts/comicsans.ttf +0 -0
  247. data/data/fonts/gkai00mp.ttf +0 -0
  248. data/data/images/16bit.dat +0 -0
  249. data/data/images/dice.dat +0 -0
  250. data/data/images/page_white_text.dat +0 -0
  251. data/data/images/rails.dat +0 -0
  252. data/data/images/rails.png +0 -0
  253. data/examples/bounding_box/bounding_boxes.rb +0 -44
  254. data/examples/bounding_box/indentation.rb +0 -35
  255. data/examples/bounding_box/russian_boxes.rb +0 -37
  256. data/examples/bounding_box/stretched_nesting.rb +0 -68
  257. data/examples/example_helper.rb +0 -8
  258. data/examples/general/background.rb +0 -24
  259. data/examples/general/canvas.rb +0 -16
  260. data/examples/general/context_sensitive_headers.rb +0 -38
  261. data/examples/general/float.rb +0 -12
  262. data/examples/general/margin.rb +0 -37
  263. data/examples/general/measurement_units.rb +0 -52
  264. data/examples/general/metadata-info.rb +0 -17
  265. data/examples/general/multi_page_layout.rb +0 -19
  266. data/examples/general/outlines.rb +0 -67
  267. data/examples/general/page_geometry.rb +0 -32
  268. data/examples/general/page_numbering.rb +0 -40
  269. data/examples/general/page_templates.rb +0 -20
  270. data/examples/general/repeaters.rb +0 -48
  271. data/examples/general/stamp.rb +0 -42
  272. data/examples/general/templates.rb +0 -14
  273. data/examples/graphics/basic_images.rb +0 -24
  274. data/examples/graphics/cmyk.rb +0 -13
  275. data/examples/graphics/curves.rb +0 -12
  276. data/examples/graphics/gradient.rb +0 -23
  277. data/examples/graphics/hexagon.rb +0 -14
  278. data/examples/graphics/image_fit.rb +0 -16
  279. data/examples/graphics/image_flow.rb +0 -38
  280. data/examples/graphics/image_position.rb +0 -18
  281. data/examples/graphics/line.rb +0 -33
  282. data/examples/graphics/png_types.rb +0 -23
  283. data/examples/graphics/polygons.rb +0 -17
  284. data/examples/graphics/remote_images.rb +0 -13
  285. data/examples/graphics/rounded_polygons.rb +0 -20
  286. data/examples/graphics/rounded_rectangle.rb +0 -21
  287. data/examples/graphics/ruport_style_helpers.rb +0 -20
  288. data/examples/graphics/stroke_bounds.rb +0 -21
  289. data/examples/graphics/stroke_cap_and_join.rb +0 -46
  290. data/examples/graphics/stroke_dash.rb +0 -43
  291. data/examples/graphics/transformations.rb +0 -53
  292. data/examples/graphics/transparency.rb +0 -27
  293. data/examples/grid/bounding_boxes.rb +0 -22
  294. data/examples/grid/column_gutter_grid.rb +0 -21
  295. data/examples/grid/multi_boxes.rb +0 -52
  296. data/examples/grid/show_grid.rb +0 -14
  297. data/examples/grid/simple_grid.rb +0 -21
  298. data/examples/m17n/chinese_text_wrapping.rb +0 -18
  299. data/examples/m17n/euro.rb +0 -16
  300. data/examples/m17n/full_win_ansi_character_list.rb +0 -20
  301. data/examples/m17n/sjis.rb +0 -29
  302. data/examples/m17n/utf8.rb +0 -14
  303. data/examples/security/hello_foo.rb +0 -9
  304. data/examples/table/bill.rb +0 -54
  305. data/examples/table/borders.rb +0 -25
  306. data/examples/table/cell.rb +0 -13
  307. data/examples/table/checkerboard.rb +0 -23
  308. data/examples/table/header.rb +0 -15
  309. data/examples/table/inline_format_table.rb +0 -13
  310. data/examples/table/multi_page_table.rb +0 -10
  311. data/examples/table/simple_table.rb +0 -25
  312. data/examples/table/subtable.rb +0 -13
  313. data/examples/table/widths.rb +0 -21
  314. data/examples/text/alignment.rb +0 -19
  315. data/examples/text/character_spacing.rb +0 -13
  316. data/examples/text/dfont.rb +0 -49
  317. data/examples/text/family_based_styling.rb +0 -25
  318. data/examples/text/font_calculations.rb +0 -92
  319. data/examples/text/font_size.rb +0 -34
  320. data/examples/text/hyphenation.rb +0 -45
  321. data/examples/text/indent_paragraphs.rb +0 -24
  322. data/examples/text/inline_format.rb +0 -104
  323. data/examples/text/kerning.rb +0 -31
  324. data/examples/text/rendering_mode.rb +0 -21
  325. data/examples/text/rotated.rb +0 -99
  326. data/examples/text/shaped_text_box.rb +0 -32
  327. data/examples/text/simple_text.rb +0 -18
  328. data/examples/text/simple_text_ttf.rb +0 -18
  329. data/examples/text/span.rb +0 -30
  330. data/examples/text/text_box.rb +0 -90
  331. data/examples/text/text_box_returning_excess.rb +0 -52
  332. data/examples/text/text_flow.rb +0 -68
  333. data/lib/prawn/compatibility.rb +0 -51
  334. data/lib/prawn/core/annotations.rb +0 -61
  335. data/lib/prawn/core/byte_string.rb +0 -9
  336. data/lib/prawn/core/destinations.rb +0 -90
  337. data/lib/prawn/core/document_state.rb +0 -78
  338. data/lib/prawn/core/literal_string.rb +0 -16
  339. data/lib/prawn/core/name_tree.rb +0 -165
  340. data/lib/prawn/core/object_store.rb +0 -264
  341. data/lib/prawn/core/page.rb +0 -213
  342. data/lib/prawn/core/pdf_object.rb +0 -108
  343. data/lib/prawn/core/reference.rb +0 -112
  344. data/lib/prawn/core/text/formatted/arranger.rb +0 -293
  345. data/lib/prawn/core/text/formatted/line_wrap.rb +0 -272
  346. data/lib/prawn/core/text/formatted/wrap.rb +0 -149
  347. data/lib/prawn/core/text.rb +0 -268
  348. data/lib/prawn/core.rb +0 -85
  349. data/lib/prawn/document/page_geometry.rb +0 -136
  350. data/lib/prawn/graphics/gradient.rb +0 -84
  351. data/spec/name_tree_spec.rb +0 -112
  352. data/spec/pdf_object_spec.rb +0 -170
  353. data/spec/template_spec.rb +0 -291
data/lib/prawn/outline.rb CHANGED
@@ -5,322 +5,20 @@
5
5
  # Author Jonathan Greenberg
6
6
 
7
7
  require 'forwardable'
8
+ require "pdf/core/outline"
8
9
 
9
10
  module Prawn
10
-
11
+
11
12
  class Document
12
13
 
14
+ # @group Experimental API
15
+
13
16
  # Lazily instantiates an Outline object for document. This is used as point of entry
14
17
  # to methods to build the outline tree.
15
18
  def outline
16
- @outline ||= Outline.new(self)
17
- end
18
-
19
- end
20
-
21
- # The Outline class organizes the outline tree items for the document.
22
- # Note that the prev and parent instance variables are adjusted while navigating
23
- # through the nested blocks. These variables along with the presence or absense
24
- # of blocks are the primary means by which the relations for the various
25
- # OutlineItems and the OutlineRoot are set. Unfortunately, the best way to
26
- # understand how this works is to follow the method calls through a real example.
27
- #
28
- # Some ideas for the organization of this class were gleaned from name_tree. In
29
- # particular the way in which the OutlineItems are finally rendered into document
30
- # objects in PdfObject through a hash.
31
- #
32
- class Outline
33
-
34
- extend Forwardable
35
- def_delegator :@document, :page_number
36
-
37
- attr_accessor :parent
38
- attr_accessor :prev
39
- attr_accessor :document
40
- attr_accessor :items
41
-
42
- def initialize(document)
43
- @document = document
44
- @parent = root
45
- @prev = nil
46
- @items = {}
47
- end
48
-
49
- # Defines/Updates an outline for the document.
50
- # The outline is an optional nested index that appears on the side of a PDF
51
- # document usually with direct links to pages. The outline DSL is defined by nested
52
- # blocks involving two methods: section and page; see the documentation on those methods
53
- # for their arguments and options. Note that one can also use outline#update
54
- # to add more sections to the end of the outline tree using the same syntax and scope.
55
- #
56
- # The syntax is best illustrated with an example:
57
- #
58
- # Prawn::Document.generate(outlined_document.pdf) do
59
- # text "Page 1. This is the first Chapter. "
60
- # start_new_page
61
- # text "Page 2. More in the first Chapter. "
62
- # start_new_page
63
- # outline.define do
64
- # section 'Chapter 1', :destination => 1, :closed => true do
65
- # page :destination => 1, :title => 'Page 1'
66
- # page :destination => 2, :title => 'Page 2'
67
- # end
68
- # end
69
- # start_new_page do
70
- # outline.update do
71
- # section 'Chapter 2', :destination => 2, do
72
- # page :destination => 3, :title => 'Page 3'
73
- # end
74
- # end
75
- # end
76
- #
77
- def define(&block)
78
- instance_eval(&block) if block
79
- end
80
-
81
- alias :update :define
82
-
83
- # Inserts an outline section to the outline tree (see outline#define).
84
- # Although you will probably choose to exclusively use outline#define so
85
- # that your outline tree is contained and easy to manage, this method
86
- # gives you the option to insert sections to the outline tree at any point
87
- # during document generation. This method allows you to add a child subsection
88
- # to any other item at any level in the outline tree.
89
- # Currently the only way to locate the place of entry is with the title for the
90
- # item. If your title names are not unique consider using define_outline.
91
- # The method takes the following arguments:
92
- # title: a string that must match an outline title to add the subsection to
93
- # position: either :first or :last(the default) where the subsection will be placed relative
94
- # to other child elements. If you need to position your subsection in between
95
- # other elements then consider using #insert_section_after
96
- # block: uses the same DSL syntax as outline#define, for example:
97
- #
98
- # Consider using this method inside of outline.update if you want to have the outline object
99
- # to be scoped as self (see #insert_section_after example).
100
- #
101
- # go_to_page 2
102
- # start_new_page
103
- # text "Inserted Page"
104
- # outline.add_subsection_to :title => 'Page 2', :first do
105
- # outline.page :destination => page_number, :title => "Inserted Page"
106
- # end
107
- #
108
- def add_subsection_to(title, position = :last, &block)
109
- @parent = items[title]
110
- raise Prawn::Errors::UnknownOutlineTitle,
111
- "\n No outline item with title: '#{title}' exists in the outline tree" unless @parent
112
- @prev = position == :first ? nil : @parent.data.last
113
- nxt = position == :first ? @parent.data.first : nil
114
- insert_section(nxt, &block)
115
- end
116
-
117
- # Inserts an outline section to the outline tree (see outline#define).
118
- # Although you will probably choose to exclusively use outline#define so
119
- # that your outline tree is contained and easy to manage, this method
120
- # gives you the option to insert sections to the outline tree at any point
121
- # during document generation. Unlike outline.add_section, this method allows
122
- # you to enter a section after any other item at any level in the outline tree.
123
- # Currently the only way to locate the place of entry is with the title for the
124
- # item. If your title names are not unique consider using define_outline.
125
- # The method takes the following arguments:
126
- # title: the title of other section or page to insert new section after
127
- # block: uses the same DSL syntax as outline#define, for example:
128
- #
129
- # go_to_page 2
130
- # start_new_page
131
- # text "Inserted Page"
132
- # update_outline do
133
- # insert_section_after :title => 'Page 2' do
134
- # page :destination => page_number, :title => "Inserted Page"
135
- # end
136
- # end
137
- #
138
- def insert_section_after(title, &block)
139
- @prev = items[title]
140
- raise Prawn::Errors::UnknownOutlineTitle,
141
- "\n No outline item with title: '#{title}' exists in the outline tree" unless @prev
142
- @parent = @prev.data.parent
143
- nxt = @prev.data.next
144
- insert_section(nxt, &block)
19
+ @outline ||= PDF::Core::Outline.new(self)
145
20
  end
146
-
147
- # See outline#define above for documentation on how this is used in that context
148
- #
149
- # Adds an outine section to the outline tree.
150
- # Although you will probably choose to exclusively use outline#define so
151
- # that your outline tree is contained and easy to manage, this method
152
- # gives you the option to add sections to the outline tree at any point
153
- # during document generation. When not being called from within another #section block
154
- # the section will be added at the top level after the other root elements of the outline.
155
- # For more flexible placement try using outline#insert_section_after and/or
156
- # outline#add_subsection_to
157
- # Takes the following arguments:
158
- # title: the outline text that appears for the section.
159
- # options: destination - optional integer defining the page number for a destination link.
160
- # - currently only :FIT destination supported with link to top of page.
161
- # closed - whether the section should show its nested outline elements.
162
- # - defaults to false.
163
- # block: more nested subsections and/or page blocks
164
- #
165
- # example usage:
166
- #
167
- # outline.section 'Added Section', :destination => 3 do
168
- # outline.page :destionation => 3, :title => 'Page 3'
169
- # end
170
- def section(title, options = {}, &block)
171
- add_outline_item(title, options, &block)
172
- end
173
-
174
- # See Outline#define above for more documentation on how it is used in that context
175
- #
176
- # Adds a page to the outline.
177
- # Although you will probably choose to exclusively use outline#define so
178
- # that your outline tree is contained and easy to manage, this method also
179
- # gives you the option to add pages to the root of outline tree at any point
180
- # during document generation. Note that the page will be added at the
181
- # top level after the other root outline elements. For more flexible placement try
182
- # using outline#insert_section_after and/or outline#add_subsection_to.
183
- #
184
- # Takes the following arguments:
185
- # options:
186
- # title - REQUIRED. The outline text that appears for the page.
187
- # destination - integer defining the page number for the destination link.
188
- # currently only :FIT destination supported with link to top of page.
189
- # closed - whether the section should show its nested outline elements.
190
- # - defaults to false.
191
- # example usage:
192
- #
193
- # outline.page :title => "Very Last Page"
194
- # Note: this method is almost identical to section except that it does not accept a block
195
- # thereby defining the outline item as a leaf on the outline tree structure.
196
- def page(options = {})
197
- if options[:title]
198
- title = options[:title]
199
- else
200
- raise Prawn::Errors::RequiredOption,
201
- "\nTitle is a required option for page"
202
- end
203
- add_outline_item(title, options)
204
- end
205
-
206
- private
207
-
208
- # The Outline dictionary (12.3.3) for this document. It is
209
- # lazily initialized, so that documents that do not have an outline
210
- # do not incur the additional overhead.
211
- def root
212
- document.state.store.root.data[:Outlines] ||= document.ref!(OutlineRoot.new)
213
- end
214
-
215
- def add_outline_item(title, options, &block)
216
- outline_item = create_outline_item(title, options)
217
- set_relations(outline_item)
218
- increase_count
219
- set_variables_for_block(outline_item, block)
220
- block.call if block
221
- reset_parent(outline_item)
222
- end
223
-
224
- def create_outline_item(title, options)
225
- outline_item = OutlineItem.new(title, parent, options)
226
21
 
227
- if options[:destination]
228
- page_index = options[:destination] - 1
229
- outline_item.dest = [document.state.pages[page_index].dictionary, :Fit]
230
- end
231
-
232
- outline_item.prev = prev if @prev
233
- items[title] = document.ref!(outline_item)
234
- end
235
-
236
- def set_relations(outline_item)
237
- prev.data.next = outline_item if prev
238
- parent.data.first = outline_item unless prev
239
- parent.data.last = outline_item
240
- end
241
-
242
- def increase_count
243
- counting_parent = parent
244
- while counting_parent
245
- counting_parent.data.count += 1
246
- if counting_parent == root
247
- counting_parent = nil
248
- else
249
- counting_parent = counting_parent.data.parent
250
- end
251
- end
252
- end
253
-
254
- def set_variables_for_block(outline_item, block)
255
- self.prev = block ? nil : outline_item
256
- self.parent = outline_item if block
257
- end
258
-
259
- def reset_parent(outline_item)
260
- if parent == outline_item
261
- self.prev = outline_item
262
- self.parent = outline_item.data.parent
263
- end
264
- end
265
-
266
- def insert_section(nxt, &block)
267
- last = @parent.data.last
268
- if block
269
- block.call
270
- end
271
- adjust_relations(nxt, last)
272
- reset_root_positioning
273
- end
274
-
275
- def adjust_relations(nxt, last)
276
- if nxt
277
- nxt.data.prev = @prev
278
- @prev.data.next = nxt
279
- @parent.data.last = last
280
- end
281
- end
282
-
283
- def reset_root_positioning
284
- @parent = root
285
- @prev = root.data.last
286
- end
287
-
288
22
  end
289
-
290
- class OutlineRoot #:nodoc:
291
- attr_accessor :count, :first, :last
292
-
293
- def initialize
294
- @count = 0
295
- end
296
-
297
- def to_hash
298
- {:Type => :Outlines, :Count => count, :First => first, :Last => last}
299
- end
300
- end
301
-
302
- class OutlineItem #:nodoc:
303
- attr_accessor :count, :first, :last, :next, :prev, :parent, :title, :dest, :closed
304
-
305
- def initialize(title, parent, options)
306
- @closed = options[:closed]
307
- @title = title
308
- @parent = parent
309
- @count = 0
310
- end
311
-
312
- def to_hash
313
- hash = { :Title => title,
314
- :Parent => parent,
315
- :Count => closed ? -count : count }
316
- [{:First => first}, {:Last => last}, {:Next => @next},
317
- {:Prev => prev}, {:Dest => dest}].each do |h|
318
- unless h.values.first.nil?
319
- hash.merge!(h)
320
- end
321
- end
322
- hash
323
- end
324
- end
23
+
325
24
  end
326
-
@@ -11,14 +11,16 @@
11
11
  module Prawn
12
12
 
13
13
  class Document
14
-
15
14
  # A list of all repeaters in the document.
16
15
  # See Document#repeat for details
17
16
  #
17
+ # @private
18
18
  def repeaters
19
19
  @repeaters ||= []
20
20
  end
21
21
 
22
+ # @group Experimental API
23
+
22
24
  # Provides a way to execute a block of code repeatedly based on a
23
25
  # page_filter. Since Stamp is used under the hood, this method is very space
24
26
  # efficient.
@@ -29,10 +31,10 @@ module Prawn
29
31
  # :even -- repeats on even pages
30
32
  # some_array -- repeats on every page listed in the array
31
33
  # some_range -- repeats on every page included in the range
32
- # some_lambda -- yields page number and repeats for true return values
34
+ # some_lambda -- yields page number and repeats for true return values
33
35
  #
34
- # Also accepts an optional second argument for dynamic content which executes the code
35
- # in the context of the filtered pages without using a Stamp.
36
+ # Also accepts an optional second argument for dynamic content which executes the code
37
+ # in the context of the filtered pages without using a Stamp.
36
38
  #
37
39
  # Example:
38
40
  #
@@ -49,8 +51,8 @@ module Prawn
49
51
  # repeat :even do
50
52
  # draw_text "EVEN", :at => [0,0]
51
53
  # end
52
- #
53
- # repeat [1,2] do
54
+ #
55
+ # repeat [1,2] do
54
56
  # draw_text "[1,2]", :at => [100,0]
55
57
  # end
56
58
  #
@@ -62,11 +64,11 @@ module Prawn
62
64
  # draw_text "Every third", :at => [250, 20]
63
65
  # end
64
66
  #
65
- # 10.times do
67
+ # 10.times do
66
68
  # start_new_page
67
69
  # draw_text "A wonderful page", :at => [400,400]
68
70
  # end
69
- #
71
+ #
70
72
  # repeat(:all, :dynamic => true) do
71
73
  # text page_number, :at => [500, 0]
72
74
  # end
@@ -108,7 +110,7 @@ module Prawn
108
110
  def run(page_number)
109
111
  if !@dynamic
110
112
  @document.stamp(@stamp_name) if match?(page_number)
111
- elsif @block
113
+ elsif @block && match?(page_number)
112
114
  @document.save_graphics_state(@graphic_state) do
113
115
  @document.send(:freeze_stamp_graphics)
114
116
  @block.call
@@ -8,6 +8,7 @@
8
8
  #
9
9
  # This is free software. Please see the LICENSE and COPYING files for details.
10
10
 
11
+ # @private
11
12
  class Arcfour
12
13
  def initialize(key)
13
14
  # Convert string key to Array of integers
@@ -7,30 +7,34 @@
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
9
  require 'digest/md5'
10
+
11
+ require 'pdf/core/byte_string'
12
+
10
13
  require 'prawn/security/arcfour'
11
- require 'prawn/core/byte_string'
12
14
 
13
15
  module Prawn
14
16
  class Document
15
-
17
+
16
18
  # Implements PDF encryption (password protection and permissions) as
17
19
  # specified in the PDF Reference, version 1.3, section 3.5 "Encryption".
18
20
  module Security
19
- include Prawn::Core
20
-
21
+ include PDF::Core
22
+
23
+ # @group Experimental API
24
+
21
25
  # Encrypts the document, to protect confidential data or control
22
26
  # modifications to the document. The encryption algorithm used is
23
27
  # detailed in the PDF Reference 1.3, section 3.5 "Encryption", and it is
24
28
  # implemented by all major PDF readers.
25
29
  #
26
30
  # +options+ can contain the following:
27
- #
28
- # <tt>:user_password</tt>:: Password required to open the document. If
31
+ #
32
+ # <tt>:user_password</tt>:: Password required to open the document. If
29
33
  # this is omitted or empty, no password will be
30
34
  # required. The document will still be
31
35
  # encrypted, but anyone can read it.
32
36
  #
33
- # <tt>:owner_password</tt>:: Password required to make modifications to
37
+ # <tt>:owner_password</tt>:: Password required to make modifications to
34
38
  # the document or change or override its
35
39
  # permissions. If this is set to
36
40
  # <tt>:random</tt>, a random password will be
@@ -52,7 +56,7 @@ module Prawn
52
56
  #
53
57
  # <tt>:copy_contents</tt>:: Copy text and graphics from document.
54
58
  #
55
- # <tt>:modify_annotations</tt>:: Add or modify text annotations and
59
+ # <tt>:modify_annotations</tt>:: Add or modify text annotations and
56
60
  # interactive form fields.
57
61
  #
58
62
  # == Examples
@@ -66,8 +70,8 @@ module Prawn
66
70
  # both the user and the owner:
67
71
  #
68
72
  # encrypt_document :user_password => 'foo', :owner_password => 'bar'
69
- #
70
- # Set no passwords, grant all permissions (This is useful because the
73
+ #
74
+ # Set no passwords, grant all permissions (This is useful because the
71
75
  # default in some readers, if no permissions are specified, is "deny"):
72
76
  #
73
77
  # encrypt_document
@@ -77,10 +81,10 @@ module Prawn
77
81
  # * The encryption used is weak; the key is password-derived and is
78
82
  # limited to 40 bits, due to US export controls in effect at the time
79
83
  # the PDF standard was written.
80
- #
84
+ #
81
85
  # * There is nothing technologically requiring PDF readers to respect the
82
86
  # permissions embedded in a document. Many PDF readers do not.
83
- #
87
+ #
84
88
  # * In short, you have <b>no security at all</b> against a moderately
85
89
  # motivated person. Don't use this for anything super-serious. This is
86
90
  # not a limitation of Prawn, but is rather a built-in limitation of the
@@ -104,7 +108,7 @@ module Prawn
104
108
  state.encrypt = true
105
109
  state.encryption_key = user_encryption_key
106
110
  end
107
-
111
+
108
112
  # Encrypts the given string under the given key, also requiring the
109
113
  # object ID and generation number of the reference.
110
114
  # See Algorithm 3.1.
@@ -136,7 +140,7 @@ module Prawn
136
140
  :modify_contents => 4,
137
141
  :copy_contents => 5,
138
142
  :modify_annotations => 6 }
139
-
143
+
140
144
  FullPermissions = 0b1111_1111_1111_1111_1111_1111_1111_1111
141
145
 
142
146
  def permissions=(perms={})
@@ -162,10 +166,10 @@ module Prawn
162
166
  @permissions || FullPermissions
163
167
  end
164
168
 
165
- PasswordPadding =
169
+ PasswordPadding =
166
170
  "28BF4E5E4E758A4164004E56FFFA01082E2E00B6D0683E802F0CA9FE6453697A".
167
171
  scan(/../).map{|x| x.to_i(16)}.pack("c*")
168
-
172
+
169
173
  # Pads or truncates a password to 32 bytes as per Alg 3.2.
170
174
  def pad_password(password)
171
175
  password = password[0, 32]
@@ -198,38 +202,41 @@ module Prawn
198
202
  end
199
203
 
200
204
  end
205
+ end
201
206
 
202
- module Core #:nodoc:
207
+ # @private
208
+ module PDF
209
+ module Core
203
210
  module_function
204
211
 
205
212
  # Like PdfObject, but returns an encrypted result if required.
206
213
  # For direct objects, requires the object identifier and generation number
207
214
  # from the indirect object referencing obj.
208
- def EncryptedPdfObject(obj, key, id, gen, in_content_stream=false)
215
+ #
216
+ # @private
217
+ def EncryptedPdfObject(obj, key, id, gen, in_content_stream=false)
209
218
  case obj
210
219
  when Array
211
220
  "[" << obj.map { |e|
212
221
  EncryptedPdfObject(e, key, id, gen, in_content_stream)
213
222
  }.join(' ') << "]"
214
223
  when LiteralString
215
- # FIXME: encrypted?
216
- obj = obj.gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
224
+ obj = ByteString.new(Prawn::Document::Security.encrypt_string(obj, key, id, gen)).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
217
225
  "(#{obj})"
218
226
  when Time
219
- # FIXME: encrypted?
220
227
  obj = obj.strftime("D:%Y%m%d%H%M%S%z").chop.chop + "'00'"
221
- obj = obj.gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
228
+ obj = ByteString.new(Prawn::Document::Security.encrypt_string(obj, key, id, gen)).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
222
229
  "(#{obj})"
223
230
  when String
224
231
  PdfObject(
225
232
  ByteString.new(
226
- Document::Security.encrypt_string(obj, key, id, gen)),
233
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen)),
227
234
  in_content_stream)
228
- when Hash
235
+ when ::Hash
229
236
  output = "<< "
230
237
  obj.each do |k,v|
231
238
  unless String === k || Symbol === k
232
- raise Prawn::Errors::FailedObjectConversion,
239
+ raise PDF::Core::Errors::FailedObjectConversion,
233
240
  "A PDF Dictionary must be keyed by names"
234
241
  end
235
242
  output << PdfObject(k.to_sym, in_content_stream) << " " <<
@@ -239,29 +246,44 @@ module Prawn
239
246
  when NameTree::Value
240
247
  PdfObject(obj.name) + " " +
241
248
  EncryptedPdfObject(obj.value, key, id, gen, in_content_stream)
249
+ when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
250
+ EncryptedPdfObject(obj.to_hash, key, id, gen, in_content_stream)
242
251
  else # delegate back to PdfObject
243
252
  PdfObject(obj, in_content_stream)
244
253
  end
245
254
  end
246
255
 
256
+
257
+ # @private
258
+ class Stream
259
+ def encrypted_object(key, id, gen)
260
+ if filtered_stream
261
+ "stream\n#{Prawn::Document::Security.encrypt_string filtered_stream, key, id, gen}\nendstream\n"
262
+ else
263
+ ''
264
+ end
265
+ end
266
+ end
267
+
268
+ # @private
247
269
  class Reference
248
270
 
249
271
  # Returns the object definition for the object this references, keyed from
250
272
  # +key+.
251
273
  def encrypted_object(key)
252
274
  @on_encode.call(self) if @on_encode
253
- output = "#{@identifier} #{gen} obj\n" <<
254
- Prawn::Core::EncryptedPdfObject(data, key, @identifier, gen) << "\n"
255
- if @stream
256
- output << "stream\n" <<
257
- Document::Security.encrypt_string(@stream, key, @identifier, gen) <<
258
- "\nendstream\n"
275
+
276
+ output = "#{@identifier} #{gen} obj\n"
277
+ unless @stream.empty?
278
+ output << PDF::Core::EncryptedPdfObject(data.merge(@stream.data), key, @identifier, gen) << "\n" <<
279
+ @stream.encrypted_object(key, @identifier, gen)
280
+ else
281
+ output << PDF::Core::EncryptedPdfObject(data, key, @identifier, gen) << "\n"
259
282
  end
283
+
260
284
  output << "endobj\n"
261
285
  end
262
286
 
263
287
  end
264
288
  end
265
-
266
289
  end
267
-