prawn 0.15.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (269) hide show
  1. data/COPYING +2 -2
  2. data/LICENSE +1 -1
  3. data/README.md +96 -0
  4. data/Rakefile +27 -30
  5. data/data/fonts/Action Man.dfont +0 -0
  6. data/data/fonts/Activa.ttf +0 -0
  7. data/data/fonts/Chalkboard.ttf +0 -0
  8. data/data/fonts/DejaVuSans.ttf +0 -0
  9. data/data/fonts/Dustismo_Roman.ttf +0 -0
  10. data/data/fonts/comicsans.ttf +0 -0
  11. data/data/fonts/gkai00mp.ttf +0 -0
  12. data/data/images/16bit.alpha +0 -0
  13. data/data/images/16bit.dat +0 -0
  14. data/data/images/dice.alpha +0 -0
  15. data/data/images/dice.dat +0 -0
  16. data/data/images/page_white_text.alpha +0 -0
  17. data/data/images/page_white_text.dat +0 -0
  18. data/data/images/rails.dat +0 -0
  19. data/data/images/rails.png +0 -0
  20. data/data/pdfs/nested_pages.pdf +13 -13
  21. data/lib/prawn.rb +21 -85
  22. data/lib/prawn/compatibility.rb +51 -0
  23. data/lib/prawn/core.rb +85 -0
  24. data/lib/prawn/core/annotations.rb +61 -0
  25. data/lib/prawn/core/byte_string.rb +9 -0
  26. data/lib/prawn/core/destinations.rb +90 -0
  27. data/lib/prawn/core/document_state.rb +78 -0
  28. data/lib/prawn/core/literal_string.rb +16 -0
  29. data/lib/prawn/core/name_tree.rb +177 -0
  30. data/lib/prawn/core/object_store.rb +264 -0
  31. data/lib/prawn/core/page.rb +215 -0
  32. data/lib/prawn/core/pdf_object.rb +108 -0
  33. data/lib/prawn/core/reference.rb +115 -0
  34. data/lib/prawn/core/text.rb +268 -0
  35. data/lib/prawn/core/text/formatted/arranger.rb +294 -0
  36. data/lib/prawn/core/text/formatted/line_wrap.rb +273 -0
  37. data/lib/prawn/core/text/formatted/wrap.rb +153 -0
  38. data/lib/prawn/document.rb +122 -155
  39. data/lib/prawn/document/bounding_box.rb +7 -36
  40. data/lib/prawn/document/column_box.rb +10 -38
  41. data/lib/prawn/document/graphics_state.rb +74 -11
  42. data/lib/prawn/document/internals.rb +23 -24
  43. data/lib/prawn/document/page_geometry.rb +136 -0
  44. data/lib/prawn/document/snapshot.rb +6 -7
  45. data/lib/prawn/document/span.rb +10 -12
  46. data/lib/prawn/encoding.rb +10 -9
  47. data/lib/prawn/errors.rb +30 -15
  48. data/lib/prawn/font.rb +104 -136
  49. data/lib/prawn/font/afm.rb +44 -46
  50. data/lib/prawn/font/dfont.rb +3 -4
  51. data/lib/prawn/font/ttf.rb +50 -31
  52. data/lib/prawn/graphics.rb +57 -302
  53. data/lib/prawn/graphics/cap_style.rb +3 -4
  54. data/lib/prawn/graphics/color.rb +5 -13
  55. data/lib/prawn/graphics/dash.rb +31 -53
  56. data/lib/prawn/graphics/gradient.rb +84 -0
  57. data/lib/prawn/graphics/join_style.rb +7 -9
  58. data/lib/prawn/graphics/transformation.rb +9 -10
  59. data/lib/prawn/graphics/transparency.rb +1 -3
  60. data/lib/prawn/images.rb +59 -69
  61. data/lib/prawn/images/image.rb +22 -6
  62. data/lib/prawn/images/jpg.rb +14 -20
  63. data/lib/prawn/images/png.rb +118 -61
  64. data/lib/prawn/layout.rb +15 -10
  65. data/lib/prawn/layout/grid.rb +54 -66
  66. data/lib/prawn/measurement_extensions.rb +6 -10
  67. data/lib/prawn/measurements.rb +21 -27
  68. data/lib/prawn/outline.rb +308 -6
  69. data/lib/prawn/repeater.rb +8 -10
  70. data/lib/prawn/security.rb +33 -55
  71. data/lib/prawn/security/arcfour.rb +0 -1
  72. data/lib/prawn/stamp.rb +3 -5
  73. data/lib/prawn/table.rb +60 -188
  74. data/lib/prawn/table/cell.rb +44 -272
  75. data/lib/prawn/table/cell/image.rb +3 -2
  76. data/lib/prawn/table/cell/in_table.rb +2 -4
  77. data/lib/prawn/table/cell/subtable.rb +2 -2
  78. data/lib/prawn/table/cell/text.rb +18 -41
  79. data/lib/prawn/table/cells.rb +48 -142
  80. data/lib/prawn/text.rb +25 -32
  81. data/lib/prawn/text/box.rb +6 -12
  82. data/lib/prawn/text/formatted.rb +4 -5
  83. data/lib/prawn/text/formatted/box.rb +59 -96
  84. data/lib/prawn/text/formatted/fragment.rb +23 -34
  85. data/lib/prawn/text/formatted/parser.rb +5 -15
  86. data/prawn.gemspec +13 -24
  87. data/spec/annotations_spec.rb +32 -16
  88. data/spec/bounding_box_spec.rb +17 -119
  89. data/spec/cell_spec.rb +42 -112
  90. data/spec/destinations_spec.rb +5 -5
  91. data/spec/document_spec.rb +111 -155
  92. data/spec/extensions/mocha.rb +0 -1
  93. data/spec/font_spec.rb +99 -149
  94. data/spec/formatted_text_arranger_spec.rb +43 -43
  95. data/spec/formatted_text_box_spec.rb +44 -43
  96. data/spec/formatted_text_fragment_spec.rb +8 -8
  97. data/spec/graphics_spec.rb +68 -151
  98. data/spec/grid_spec.rb +15 -26
  99. data/spec/images_spec.rb +30 -51
  100. data/spec/inline_formatted_text_parser_spec.rb +20 -69
  101. data/spec/jpg_spec.rb +4 -4
  102. data/spec/line_wrap_spec.rb +28 -28
  103. data/spec/measurement_units_spec.rb +6 -6
  104. data/spec/name_tree_spec.rb +112 -0
  105. data/spec/object_store_spec.rb +106 -17
  106. data/spec/outline_spec.rb +63 -103
  107. data/spec/pdf_object_spec.rb +170 -0
  108. data/spec/png_spec.rb +25 -25
  109. data/spec/reference_spec.rb +65 -8
  110. data/spec/repeater_spec.rb +10 -10
  111. data/spec/security_spec.rb +12 -44
  112. data/spec/snapshot_spec.rb +7 -7
  113. data/spec/span_spec.rb +15 -10
  114. data/spec/spec_helper.rb +8 -32
  115. data/spec/stamp_spec.rb +30 -29
  116. data/spec/stroke_styles_spec.rb +18 -36
  117. data/spec/table_spec.rb +111 -706
  118. data/spec/template_spec.rb +297 -0
  119. data/spec/text_at_spec.rb +33 -19
  120. data/spec/text_box_spec.rb +64 -100
  121. data/spec/text_rendering_mode_spec.rb +5 -5
  122. data/spec/text_spacing_spec.rb +4 -4
  123. data/spec/text_spec.rb +64 -84
  124. data/spec/transparency_spec.rb +5 -5
  125. metadata +290 -463
  126. checksums.yaml +0 -7
  127. data/.yardopts +0 -10
  128. data/Gemfile +0 -11
  129. data/data/images/16bit.color +0 -0
  130. data/data/images/dice.color +0 -0
  131. data/data/images/indexed_color.dat +0 -0
  132. data/data/images/indexed_color.png +0 -0
  133. data/data/images/page_white_text.color +0 -0
  134. data/lib/prawn/font_metric_cache.rb +0 -47
  135. data/lib/prawn/graphics/patterns.rb +0 -138
  136. data/lib/prawn/image_handler.rb +0 -36
  137. data/lib/prawn/soft_mask.rb +0 -96
  138. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  139. data/lib/prawn/table/column_width_calculator.rb +0 -61
  140. data/lib/prawn/text/formatted/arranger.rb +0 -290
  141. data/lib/prawn/text/formatted/line_wrap.rb +0 -266
  142. data/lib/prawn/text/formatted/wrap.rb +0 -150
  143. data/lib/prawn/utilities.rb +0 -46
  144. data/manual/basic_concepts/adding_pages.rb +0 -27
  145. data/manual/basic_concepts/basic_concepts.rb +0 -34
  146. data/manual/basic_concepts/creation.rb +0 -39
  147. data/manual/basic_concepts/cursor.rb +0 -33
  148. data/manual/basic_concepts/measurement.rb +0 -25
  149. data/manual/basic_concepts/origin.rb +0 -38
  150. data/manual/basic_concepts/other_cursor_helpers.rb +0 -40
  151. data/manual/bounding_box/bounding_box.rb +0 -39
  152. data/manual/bounding_box/bounds.rb +0 -49
  153. data/manual/bounding_box/canvas.rb +0 -24
  154. data/manual/bounding_box/creation.rb +0 -23
  155. data/manual/bounding_box/indentation.rb +0 -46
  156. data/manual/bounding_box/nesting.rb +0 -45
  157. data/manual/bounding_box/russian_boxes.rb +0 -40
  158. data/manual/bounding_box/stretchy.rb +0 -31
  159. data/manual/document_and_page_options/background.rb +0 -27
  160. data/manual/document_and_page_options/document_and_page_options.rb +0 -32
  161. data/manual/document_and_page_options/metadata.rb +0 -23
  162. data/manual/document_and_page_options/page_margins.rb +0 -38
  163. data/manual/document_and_page_options/page_size.rb +0 -34
  164. data/manual/document_and_page_options/print_scaling.rb +0 -20
  165. data/manual/example_file.rb +0 -111
  166. data/manual/example_helper.rb +0 -411
  167. data/manual/example_package.rb +0 -53
  168. data/manual/example_section.rb +0 -46
  169. data/manual/graphics/circle_and_ellipse.rb +0 -22
  170. data/manual/graphics/color.rb +0 -24
  171. data/manual/graphics/common_lines.rb +0 -30
  172. data/manual/graphics/fill_and_stroke.rb +0 -42
  173. data/manual/graphics/fill_rules.rb +0 -37
  174. data/manual/graphics/gradients.rb +0 -37
  175. data/manual/graphics/graphics.rb +0 -58
  176. data/manual/graphics/helper.rb +0 -24
  177. data/manual/graphics/line_width.rb +0 -35
  178. data/manual/graphics/lines_and_curves.rb +0 -41
  179. data/manual/graphics/polygon.rb +0 -29
  180. data/manual/graphics/rectangle.rb +0 -21
  181. data/manual/graphics/rotate.rb +0 -28
  182. data/manual/graphics/scale.rb +0 -41
  183. data/manual/graphics/soft_masks.rb +0 -46
  184. data/manual/graphics/stroke_cap.rb +0 -31
  185. data/manual/graphics/stroke_dash.rb +0 -48
  186. data/manual/graphics/stroke_join.rb +0 -30
  187. data/manual/graphics/translate.rb +0 -29
  188. data/manual/graphics/transparency.rb +0 -35
  189. data/manual/images/absolute_position.rb +0 -23
  190. data/manual/images/fit.rb +0 -21
  191. data/manual/images/horizontal.rb +0 -25
  192. data/manual/images/images.rb +0 -40
  193. data/manual/images/plain_image.rb +0 -18
  194. data/manual/images/scale.rb +0 -22
  195. data/manual/images/vertical.rb +0 -28
  196. data/manual/images/width_and_height.rb +0 -25
  197. data/manual/layout/boxes.rb +0 -27
  198. data/manual/layout/content.rb +0 -25
  199. data/manual/layout/layout.rb +0 -28
  200. data/manual/layout/simple_grid.rb +0 -23
  201. data/manual/manual/cover.rb +0 -36
  202. data/manual/manual/foreword.rb +0 -85
  203. data/manual/manual/how_to_read_this_manual.rb +0 -41
  204. data/manual/manual/manual.rb +0 -34
  205. data/manual/outline/add_subsection_to.rb +0 -61
  206. data/manual/outline/insert_section_after.rb +0 -47
  207. data/manual/outline/outline.rb +0 -32
  208. data/manual/outline/sections_and_pages.rb +0 -67
  209. data/manual/repeatable_content/page_numbering.rb +0 -54
  210. data/manual/repeatable_content/repeatable_content.rb +0 -31
  211. data/manual/repeatable_content/repeater.rb +0 -55
  212. data/manual/repeatable_content/stamp.rb +0 -41
  213. data/manual/security/encryption.rb +0 -31
  214. data/manual/security/permissions.rb +0 -38
  215. data/manual/security/security.rb +0 -28
  216. data/manual/syntax_highlight.rb +0 -52
  217. data/manual/table/basic_block.rb +0 -53
  218. data/manual/table/before_rendering_page.rb +0 -26
  219. data/manual/table/cell_border_lines.rb +0 -24
  220. data/manual/table/cell_borders_and_bg.rb +0 -31
  221. data/manual/table/cell_dimensions.rb +0 -30
  222. data/manual/table/cell_text.rb +0 -38
  223. data/manual/table/column_widths.rb +0 -30
  224. data/manual/table/content_and_subtables.rb +0 -39
  225. data/manual/table/creation.rb +0 -27
  226. data/manual/table/filtering.rb +0 -36
  227. data/manual/table/flow_and_header.rb +0 -17
  228. data/manual/table/image_cells.rb +0 -33
  229. data/manual/table/position.rb +0 -29
  230. data/manual/table/row_colors.rb +0 -20
  231. data/manual/table/span.rb +0 -30
  232. data/manual/table/style.rb +0 -22
  233. data/manual/table/table.rb +0 -52
  234. data/manual/table/width.rb +0 -27
  235. data/manual/text/alignment.rb +0 -44
  236. data/manual/text/color.rb +0 -24
  237. data/manual/text/column_box.rb +0 -32
  238. data/manual/text/fallback_fonts.rb +0 -37
  239. data/manual/text/font.rb +0 -41
  240. data/manual/text/font_size.rb +0 -45
  241. data/manual/text/font_style.rb +0 -23
  242. data/manual/text/formatted_callbacks.rb +0 -60
  243. data/manual/text/formatted_text.rb +0 -54
  244. data/manual/text/free_flowing_text.rb +0 -51
  245. data/manual/text/group.rb +0 -31
  246. data/manual/text/inline.rb +0 -43
  247. data/manual/text/kerning_and_character_spacing.rb +0 -39
  248. data/manual/text/leading.rb +0 -25
  249. data/manual/text/line_wrapping.rb +0 -41
  250. data/manual/text/paragraph_indentation.rb +0 -26
  251. data/manual/text/positioned_text.rb +0 -38
  252. data/manual/text/registering_families.rb +0 -48
  253. data/manual/text/rendering_and_color.rb +0 -37
  254. data/manual/text/right_to_left_text.rb +0 -43
  255. data/manual/text/rotation.rb +0 -43
  256. data/manual/text/single_usage.rb +0 -37
  257. data/manual/text/text.rb +0 -75
  258. data/manual/text/text_box_excess.rb +0 -32
  259. data/manual/text/text_box_extensions.rb +0 -45
  260. data/manual/text/text_box_overflow.rb +0 -44
  261. data/manual/text/utf8.rb +0 -28
  262. data/manual/text/win_ansi_charset.rb +0 -59
  263. data/spec/acceptance/png.rb +0 -23
  264. data/spec/column_box_spec.rb +0 -65
  265. data/spec/extensions/encoding_helpers.rb +0 -9
  266. data/spec/font_metric_cache_spec.rb +0 -52
  267. data/spec/image_handler_spec.rb +0 -54
  268. data/spec/soft_mask_spec.rb +0 -117
  269. data/spec/table/span_dummy_spec.rb +0 -17
@@ -0,0 +1,153 @@
1
+ require "prawn/core/text/formatted/line_wrap"
2
+ require "prawn/core/text/formatted/arranger"
3
+
4
+ module Prawn
5
+ module Core
6
+ module Text
7
+ module Formatted #:nodoc:
8
+ module Wrap #:nodoc:
9
+
10
+ def initialize(array, options)
11
+ @line_wrap = Prawn::Core::Text::Formatted::LineWrap.new
12
+ @arranger = Prawn::Core::Text::Formatted::Arranger.new(@document,
13
+ :kerning => options[:kerning])
14
+ end
15
+
16
+
17
+ # See the developer documentation for Prawn::Core::Text#wrap
18
+ #
19
+ # Formatted#wrap should set the following variables:
20
+ # <tt>@line_height</tt>::
21
+ # the height of the tallest fragment in the last printed line
22
+ # <tt>@descender</tt>::
23
+ # the descender height of the tallest fragment in the last
24
+ # printed line
25
+ # <tt>@ascender</tt>::
26
+ # the ascender heigth of the tallest fragment in the last
27
+ # printed line
28
+ # <tt>@baseline_y</tt>::
29
+ # the baseline of the current line
30
+ # <tt>@nothing_printed</tt>::
31
+ # set to true until something is printed, then false
32
+ # <tt>@everything_printed</tt>::
33
+ # set to false until everything printed, then true
34
+ #
35
+ # Returns any formatted text that was not printed
36
+ #
37
+ def wrap(array) #:nodoc:
38
+ initialize_wrap(array)
39
+
40
+ stop = false
41
+ while !stop
42
+ # wrap before testing if enough height for this line because the
43
+ # height of the highest fragment on this line will be used to
44
+ # determine the line height
45
+ @line_wrap.wrap_line(:document => @document,
46
+ :kerning => @kerning,
47
+ :width => available_width,
48
+ :arranger => @arranger)
49
+
50
+ if enough_height_for_this_line?
51
+ move_baseline_down
52
+ print_line
53
+ else
54
+ stop = true
55
+ end
56
+
57
+ stop ||= @single_line || @arranger.finished?
58
+ end
59
+ @text = @printed_lines.join("\n")
60
+ @everything_printed = @arranger.finished?
61
+ @arranger.unconsumed
62
+ end
63
+
64
+ private
65
+
66
+ def print_line
67
+ @nothing_printed = false
68
+ printed_fragments = []
69
+ fragments_this_line = []
70
+
71
+ word_spacing = word_spacing_for_this_line
72
+ while fragment = @arranger.retrieve_fragment
73
+ fragment.word_spacing = word_spacing
74
+ if fragment.text == "\n"
75
+ printed_fragments << "\n" if @printed_lines.last == ""
76
+ break
77
+ end
78
+ printed_fragments << fragment.text
79
+ fragments_this_line << fragment
80
+ end
81
+
82
+ accumulated_width = 0
83
+ fragments_this_line.reverse! if @direction == :rtl
84
+ fragments_this_line.each do |fragment|
85
+ fragment.default_direction = @direction
86
+ format_and_draw_fragment(fragment, accumulated_width,
87
+ @line_wrap.width, word_spacing)
88
+ accumulated_width += fragment.width
89
+ end
90
+
91
+ if "".respond_to?(:force_encoding)
92
+ printed_fragments.map! { |s| s.force_encoding("utf-8") }
93
+ end
94
+ @printed_lines << printed_fragments.join
95
+ end
96
+
97
+ def word_spacing_for_this_line
98
+ if @align == :justify &&
99
+ @line_wrap.space_count > 0 &&
100
+ !@line_wrap.paragraph_finished?
101
+ (available_width - @line_wrap.width) / @line_wrap.space_count
102
+ else
103
+ 0
104
+ end
105
+ end
106
+
107
+ def enough_height_for_this_line?
108
+ @line_height = @arranger.max_line_height
109
+ @descender = @arranger.max_descender
110
+ @ascender = @arranger.max_ascender
111
+ if @baseline_y == 0
112
+ diff = @ascender + @descender
113
+ else
114
+ diff = @descender + @line_height + @leading
115
+ end
116
+ required_total_height = @baseline_y.abs + diff
117
+ if required_total_height > @height + 0.0001
118
+ # no room for the full height of this line
119
+ @arranger.repack_unretrieved
120
+ false
121
+ else
122
+ true
123
+ end
124
+ end
125
+
126
+ def initialize_wrap(array)
127
+ @text = nil
128
+ @arranger.format_array = array
129
+
130
+ # these values will depend on the maximum value within a given line
131
+ @line_height = 0
132
+ @descender = 0
133
+ @ascender = 0
134
+ @baseline_y = 0
135
+
136
+ @printed_lines = []
137
+ @nothing_printed = true
138
+ @everything_printed = false
139
+ end
140
+
141
+ def format_and_draw_fragment(fragment, accumulated_width,
142
+ line_width, word_spacing)
143
+ @arranger.apply_color_and_font_settings(fragment) do
144
+ draw_fragment(fragment, accumulated_width,
145
+ line_width, word_spacing)
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -7,13 +7,13 @@
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
9
  require "stringio"
10
-
11
- require_relative "document/bounding_box"
12
- require_relative "document/column_box"
13
- require_relative "document/internals"
14
- require_relative "document/span"
15
- require_relative "document/snapshot"
16
- require_relative "document/graphics_state"
10
+ require "prawn/document/page_geometry"
11
+ require "prawn/document/bounding_box"
12
+ require "prawn/document/column_box"
13
+ require "prawn/document/internals"
14
+ require "prawn/document/span"
15
+ require "prawn/document/snapshot"
16
+ require "prawn/document/graphics_state"
17
17
 
18
18
  module Prawn
19
19
 
@@ -52,8 +52,8 @@ module Prawn
52
52
  #
53
53
  class Document
54
54
  include Prawn::Document::Internals
55
- include PDF::Core::Annotations
56
- include PDF::Core::Destinations
55
+ include Prawn::Core::Annotations
56
+ include Prawn::Core::Destinations
57
57
  include Prawn::Document::Snapshot
58
58
  include Prawn::Document::GraphicsState
59
59
  include Prawn::Document::Security
@@ -61,17 +61,6 @@ module Prawn
61
61
  include Prawn::Graphics
62
62
  include Prawn::Images
63
63
  include Prawn::Stamp
64
- include Prawn::SoftMask
65
-
66
- # @group Extension API
67
-
68
- # NOTE: We probably need to rethink the options validation system, but this
69
- # constant temporarily allows for extensions to modify the list.
70
-
71
- VALID_OPTIONS = [:page_size, :page_layout, :margin, :left_margin,
72
- :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
73
- :compress, :skip_encoding, :background, :info,
74
- :optimize_objects, :text_formatter, :print_scaling]
75
64
 
76
65
  # Any module added to this array will be included into instances of
77
66
  # Prawn::Document at the per-object level. These will also be inherited by
@@ -93,28 +82,14 @@ module Prawn
93
82
  # party!
94
83
  # end
95
84
  #
96
- #
97
85
  def self.extensions
98
86
  @extensions ||= []
99
87
  end
100
88
 
101
- # @private
102
- def self.inherited(base)
89
+ def self.inherited(base) #:nodoc:
103
90
  extensions.each { |e| base.extensions << e }
104
91
  end
105
92
 
106
- # @group Stable Attributes
107
-
108
- attr_accessor :margin_box
109
- attr_reader :margins, :y
110
- attr_accessor :page_number
111
-
112
- # @group Extension Attributes
113
-
114
- attr_accessor :text_formatter
115
-
116
- # @group Stable API
117
-
118
93
  # Creates and renders a PDF document.
119
94
  #
120
95
  # When using the implicit block form, Prawn will evaluate the block
@@ -161,9 +136,8 @@ module Prawn
161
136
  # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
162
137
  # <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
163
138
  # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
164
- # <tt>:background_scale</tt>:: Backgound image scale [1] [nil]
165
139
  # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
166
- # <tt>:text_formatter</tt>: The text formatter to use for <tt>:inline_format</tt>ted text [Prawn::Text::Formatted::Parser]
140
+ # <tt>:template</tt>:: The path to an existing PDF file to use as a template [nil]
167
141
  #
168
142
  # Setting e.g. the :margin to 100 points and the :left_margin to 50 will result in margins
169
143
  # of 100 points on every side except for the left, where it will be 50.
@@ -192,25 +166,25 @@ module Prawn
192
166
  # pdf = Prawn::Document.new(:page_size => [200, 300])
193
167
  #
194
168
  # # New document, with background
195
- # pdf = Prawn::Document.new(:background => "#{Prawn::DATADIR}/images/pigs.jpg")
169
+ # pdf = Prawn::Document.new(:background => "#{Prawn::BASEDIR}/data/images/pigs.jpg")
196
170
  #
197
171
  def initialize(options={},&block)
198
172
  options = options.dup
199
173
 
200
- Prawn.verify_options VALID_OPTIONS, options
174
+ Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
175
+ :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
176
+ :compress, :skip_encoding, :background, :info,
177
+ :optimize_objects, :template], options
201
178
 
202
179
  # need to fix, as the refactoring breaks this
203
180
  # raise NotImplementedError if options[:skip_page_creation]
204
181
 
205
182
  self.class.extensions.reverse_each { |e| extend e }
206
- @internal_state = PDF::Core::DocumentState.new(options)
183
+ @internal_state = Prawn::Core::DocumentState.new(options)
207
184
  @internal_state.populate_pages_from_store(self)
208
185
  min_version(state.store.min_version) if state.store.min_version
209
186
 
210
- min_version(1.6) if options[:print_scaling] == :none
211
-
212
187
  @background = options[:background]
213
- @background_scale = options[:background_scale] || 1
214
188
  @font_size = 12
215
189
 
216
190
  @bounding_box = nil
@@ -218,12 +192,19 @@ module Prawn
218
192
 
219
193
  @page_number = 0
220
194
 
221
- @text_formatter = options.delete(:text_formatter) || Text::Formatted::Parser
222
-
223
195
  options[:size] = options.delete(:page_size)
224
196
  options[:layout] = options.delete(:page_layout)
225
197
 
226
- initialize_first_page(options)
198
+ if options[:template]
199
+ fresh_content_streams(options)
200
+ go_to_page(1)
201
+ else
202
+ if options[:skip_page_creation] || options[:template]
203
+ start_new_page(options.merge(:orphan => true))
204
+ else
205
+ start_new_page(options)
206
+ end
207
+ end
227
208
 
228
209
  @bounding_box = @margin_box
229
210
 
@@ -232,7 +213,18 @@ module Prawn
232
213
  end
233
214
  end
234
215
 
235
- # @group Stable API
216
+ attr_accessor :margin_box
217
+ attr_reader :margins, :y
218
+ attr_writer :font_size
219
+ attr_accessor :page_number
220
+
221
+ def state
222
+ @internal_state
223
+ end
224
+
225
+ def page
226
+ state.page
227
+ end
236
228
 
237
229
  # Creates and advances to a new page in the document.
238
230
  #
@@ -244,6 +236,11 @@ module Prawn
244
236
  # pdf.start_new_page(:left_margin => 50, :right_margin => 50)
245
237
  # pdf.start_new_page(:margin => 100)
246
238
  #
239
+ # A template for a page can be specified by pointing to the path of and existing pdf.
240
+ # One can also specify which page of the template which defaults otherwise to 1.
241
+ #
242
+ # pdf.start_new_page(:template => multipage_template.pdf, :template_page => 2)
243
+ #
247
244
  def start_new_page(options = {})
248
245
  if last_page = state.page
249
246
  last_page_size = last_page.size
@@ -255,13 +252,14 @@ module Prawn
255
252
  :layout => options[:layout] || last_page_layout,
256
253
  :margins => last_page_margins}
257
254
  if last_page
258
- new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
255
+ new_graphic_state = last_page.graphic_state.dup
259
256
  #erase the color space so that it gets reset on new page for fussy pdf-readers
260
- new_graphic_state.color_space = {} if new_graphic_state
257
+ new_graphic_state.color_space = {}
261
258
  page_options.merge!(:graphic_state => new_graphic_state)
262
259
  end
260
+ merge_template_options(page_options, options) if options[:template]
263
261
 
264
- state.page = PDF::Core::Page.new(self, page_options)
262
+ state.page = Prawn::Core::Page.new(self, page_options)
265
263
 
266
264
  apply_margin_options(options)
267
265
  generate_margin_box
@@ -272,13 +270,14 @@ module Prawn
272
270
  @bounding_box = @margin_box
273
271
  end
274
272
 
275
- use_graphic_settings
273
+ state.page.new_content_stream if options[:template]
274
+ use_graphic_settings(options[:template])
276
275
 
277
276
  unless options[:orphan]
278
277
  state.insert_page(state.page, @page_number)
279
278
  @page_number += 1
280
279
 
281
- canvas { image(@background, :scale => @background_scale, :at => bounds.top_left) } if @background
280
+ canvas { image(@background, :at => bounds.top_left) } if @background
282
281
  @y = @bounding_box.absolute_top
283
282
 
284
283
  float do
@@ -349,26 +348,19 @@ module Prawn
349
348
  self.y = original_y
350
349
  end
351
350
 
352
- # Renders the PDF document to string.
353
- # Pass an open file descriptor to render to file.
351
+ # Renders the PDF document to string
354
352
  #
355
- def render(output = StringIO.new)
356
- if output.instance_of?(StringIO)
357
- output.set_encoding(::Encoding::ASCII_8BIT)
358
- end
353
+ def render
354
+ output = StringIO.new
359
355
  finalize_all_page_contents
360
356
 
361
357
  render_header(output)
362
358
  render_body(output)
363
359
  render_xref(output)
364
360
  render_trailer(output)
365
- if output.instance_of?(StringIO)
366
- str = output.string
367
- str.force_encoding(::Encoding::ASCII_8BIT)
368
- return str
369
- else
370
- return nil
371
- end
361
+ str = output.string
362
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
363
+ str
372
364
  end
373
365
 
374
366
  # Renders the PDF document to file.
@@ -376,7 +368,8 @@ module Prawn
376
368
  # pdf.render_file "foo.pdf"
377
369
  #
378
370
  def render_file(filename)
379
- File.open(filename, "wb") { |f| render(f) }
371
+ Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
372
+ File.open(filename,mode) { |f| f << render }
380
373
  end
381
374
 
382
375
  # The bounds method returns the current bounding box you are currently in,
@@ -412,7 +405,6 @@ module Prawn
412
405
 
413
406
  # Returns the innermost non-stretchy bounding box.
414
407
  #
415
- # @private
416
408
  def reference_bounds
417
409
  @bounding_box.reference_bounds
418
410
  end
@@ -498,6 +490,47 @@ module Prawn
498
490
  bounds.indent(left, right, &block)
499
491
  end
500
492
 
493
+
494
+ def mask(*fields) # :nodoc:
495
+ # Stores the current state of the named attributes, executes the block, and
496
+ # then restores the original values after the block has executed.
497
+ # -- I will remove the nodoc if/when this feature is a little less hacky
498
+ stored = {}
499
+ fields.each { |f| stored[f] = send(f) }
500
+ yield
501
+ fields.each { |f| send("#{f}=", stored[f]) }
502
+ end
503
+
504
+ # Attempts to group the given block vertically within the current context.
505
+ # First attempts to render it in the current position on the current page.
506
+ # If that attempt overflows, it is tried anew after starting a new context
507
+ # (page or column). Returns a logically true value if the content fits in
508
+ # one page/column, false if a new page or column was needed.
509
+ #
510
+ # Raises CannotGroup if the provided content is too large to fit alone in
511
+ # the current page or column.
512
+ #
513
+ def group(second_attempt=false)
514
+ old_bounding_box = @bounding_box
515
+ @bounding_box = SimpleDelegator.new(@bounding_box)
516
+
517
+ def @bounding_box.move_past_bottom
518
+ raise RollbackTransaction
519
+ end
520
+
521
+ success = transaction { yield }
522
+
523
+ @bounding_box = old_bounding_box
524
+
525
+ unless success
526
+ raise Prawn::Errors::CannotGroup if second_attempt
527
+ old_bounding_box.move_past_bottom
528
+ group(second_attempt=true) { yield }
529
+ end
530
+
531
+ success
532
+ end
533
+
501
534
  # Places a text box on specified pages for page numbering. This should be called
502
535
  # towards the end of document creation, after all your content is already in
503
536
  # place. In your template string, <page> refers to the current page, and
@@ -506,15 +539,15 @@ module Prawn
506
539
  # through existing pages after they are created.
507
540
  #
508
541
  # Parameters are:
509
- #
510
- # <tt>string</tt>:: Template string for page number wording.
542
+ #
543
+ # <tt>string</tt>:: Template string for page number wording.
511
544
  # Should include '<page>' and, optionally, '<total>'.
512
545
  # <tt>options</tt>:: A hash for page numbering and text box options.
513
- # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
546
+ # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
514
547
  # Refer to the method 'page_match?'
515
548
  # <tt>:start_count_at</tt>:: The starting count to increment pages from.
516
549
  # <tt>:total_pages</tt>:: If provided, will replace <total> with the value given.
517
- # Useful to override the total number of pages when using
550
+ # Useful to override the total number of pages when using
518
551
  # the start_count_at option.
519
552
  # <tt>:color</tt>:: Text fill color.
520
553
  #
@@ -525,7 +558,7 @@ module Prawn
525
558
  # five.
526
559
  #
527
560
  # Prawn::Document.generate("page_with_numbering.pdf") do
528
- # number_pages "<page> in a total of <total>",
561
+ # number_pages "<page> in a total of <total>",
529
562
  # {:start_count_at => 5,
530
563
  # :page_filter => lambda{ |pg| pg != 1 },
531
564
  # :at => [bounds.right - 50, 0],
@@ -544,8 +577,8 @@ module Prawn
544
577
  total_pages = opts.delete(:total_pages)
545
578
  txtcolor = opts.delete(:color)
546
579
  # An explicit height so that we can draw page numbers in the margins
547
- opts[:height] = 50 unless opts.has_key?(:height)
548
-
580
+ opts[:height] = 50
581
+
549
582
  start_count = false
550
583
  pseudopage = 0
551
584
  (1..page_count).each do |p|
@@ -556,7 +589,7 @@ module Prawn
556
589
  else
557
590
  start_count_at.to_i
558
591
  end
559
- end
592
+ end
560
593
  if page_match?(page_filter, p)
561
594
  go_to_page(p)
562
595
  # have to use fill_color here otherwise text reverts back to default fill color
@@ -565,53 +598,13 @@ module Prawn
565
598
  str = string.gsub("<page>","#{pseudopage}").gsub("<total>","#{total_pages}")
566
599
  text_box str, opts
567
600
  start_count = true # increment page count as soon as first match found
568
- end
601
+ end
569
602
  pseudopage += 1 if start_count
570
603
  end
571
604
  end
572
605
 
573
- # Returns true if content streams will be compressed before rendering,
574
- # false otherwise
575
- #
576
- def compression_enabled?
577
- !!state.compress
578
- end
579
-
580
- # @group Experimental API
581
-
582
- # Attempts to group the given block vertically within the current context.
583
- # First attempts to render it in the current position on the current page.
584
- # If that attempt overflows, it is tried anew after starting a new context
585
- # (page or column). Returns a logically true value if the content fits in
586
- # one page/column, false if a new page or column was needed.
587
- #
588
- # Raises CannotGroup if the provided content is too large to fit alone in
589
- # the current page or column.
590
- #
591
- def group(second_attempt=false)
592
- old_bounding_box = @bounding_box
593
- @bounding_box = SimpleDelegator.new(@bounding_box)
594
-
595
- # @private
596
- def @bounding_box.move_past_bottom
597
- raise RollbackTransaction
598
- end
599
-
600
- success = transaction { yield }
601
-
602
- @bounding_box = old_bounding_box
603
-
604
- unless success
605
- raise Prawn::Errors::CannotGroup if second_attempt
606
- old_bounding_box.move_past_bottom
607
- group(second_attempt=true) { yield }
608
- end
609
-
610
- success
611
- end
612
-
613
606
  # Provides a way to execute a block of code repeatedly based on a
614
- # page_filter.
607
+ # page_filter.
615
608
  #
616
609
  # Available page filters are:
617
610
  # :all repeats on every page
@@ -619,7 +612,7 @@ module Prawn
619
612
  # :even repeats on even pages
620
613
  # some_array repeats on every page listed in the array
621
614
  # some_range repeats on every page included in the range
622
- # some_lambda yields page number and repeats for true return values
615
+ # some_lambda yields page number and repeats for true return values
623
616
  def page_match?(page_filter, page_number)
624
617
  case page_filter
625
618
  when :all
@@ -633,47 +626,25 @@ module Prawn
633
626
  when Proc
634
627
  page_filter.call(page_number)
635
628
  end
636
- end
637
-
638
- # @private
639
-
640
- def mask(*fields)
641
- # Stores the current state of the named attributes, executes the block, and
642
- # then restores the original values after the block has executed.
643
- # -- I will remove the nodoc if/when this feature is a little less hacky
644
- stored = {}
645
- fields.each { |f| stored[f] = send(f) }
646
- yield
647
- fields.each { |f| send("#{f}=", stored[f]) }
648
- end
649
-
650
- # @group Extension API
651
-
652
- def initialize_first_page(options)
653
- if options[:skip_page_creation]
654
- start_new_page(options.merge(:orphan => true))
655
- else
656
- start_new_page(options)
657
- end
658
- end
629
+ end
659
630
 
660
- ## Internals. Don't depend on them!
661
631
 
662
- # @private
663
- def state
664
- @internal_state
665
- end
666
-
667
- # @private
668
- def page
669
- state.page
632
+ # Returns true if content streams will be compressed before rendering,
633
+ # false otherwise
634
+ #
635
+ def compression_enabled?
636
+ !!state.compress
670
637
  end
671
638
 
672
639
  private
673
640
 
641
+ def merge_template_options(page_options, options)
642
+ object_id = state.store.import_page(options[:template], options[:template_page] || 1)
643
+ page_options.merge!(:object_id => object_id )
644
+ end
674
645
 
675
646
  # setting override_settings to true ensures that a new graphic state does not end up using
676
- # previous settings.
647
+ # previous settings especially from imported template streams
677
648
  def use_graphic_settings(override_settings = false)
678
649
  set_fill_color if current_fill_color != "000000" || override_settings
679
650
  set_stroke_color if current_stroke_color != "000000" || override_settings
@@ -726,9 +697,5 @@ module Prawn
726
697
  end
727
698
  end
728
699
  end
729
-
730
- def font_metric_cache #:nodoc:
731
- @font_metric_cache ||= FontMetricCache.new( self )
732
- end
733
700
  end
734
701
  end