prawn 1.0.0.rc2 → 1.0.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 (169) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/COPYING +2 -2
  4. data/Gemfile +8 -15
  5. data/LICENSE +1 -1
  6. data/Rakefile +25 -16
  7. data/data/images/16bit.alpha +0 -0
  8. data/data/images/16bit.color +0 -0
  9. data/data/images/dice.alpha +0 -0
  10. data/data/images/dice.color +0 -0
  11. data/data/images/indexed_color.dat +0 -0
  12. data/data/images/indexed_color.png +0 -0
  13. data/data/images/license.md +8 -0
  14. data/data/images/page_white_text.alpha +0 -0
  15. data/data/images/page_white_text.color +0 -0
  16. data/lib/prawn.rb +85 -23
  17. data/lib/prawn/document.rb +134 -116
  18. data/lib/prawn/document/bounding_box.rb +33 -4
  19. data/lib/prawn/document/column_box.rb +18 -6
  20. data/lib/prawn/document/graphics_state.rb +11 -74
  21. data/lib/prawn/document/internals.rb +24 -23
  22. data/lib/prawn/document/span.rb +12 -10
  23. data/lib/prawn/encoding.rb +8 -9
  24. data/lib/prawn/errors.rb +13 -32
  25. data/lib/prawn/font.rb +137 -105
  26. data/lib/prawn/font/afm.rb +76 -32
  27. data/lib/prawn/font/dfont.rb +4 -3
  28. data/lib/prawn/font/ttf.rb +33 -25
  29. data/lib/prawn/font_metric_cache.rb +47 -0
  30. data/lib/prawn/graphics.rb +177 -57
  31. data/lib/prawn/graphics/cap_style.rb +4 -3
  32. data/lib/prawn/graphics/color.rb +5 -4
  33. data/lib/prawn/graphics/dash.rb +53 -31
  34. data/lib/prawn/graphics/join_style.rb +9 -7
  35. data/lib/prawn/graphics/patterns.rb +4 -15
  36. data/lib/prawn/graphics/transformation.rb +10 -9
  37. data/lib/prawn/graphics/transparency.rb +3 -1
  38. data/lib/prawn/{layout/grid.rb → grid.rb} +72 -54
  39. data/lib/prawn/image_handler.rb +42 -0
  40. data/lib/prawn/images.rb +58 -54
  41. data/lib/prawn/images/image.rb +6 -22
  42. data/lib/prawn/images/jpg.rb +20 -14
  43. data/lib/prawn/images/png.rb +58 -121
  44. data/lib/prawn/layout.rb +12 -15
  45. data/lib/prawn/measurement_extensions.rb +10 -6
  46. data/lib/prawn/measurements.rb +27 -21
  47. data/lib/prawn/outline.rb +108 -147
  48. data/lib/prawn/repeater.rb +10 -8
  49. data/lib/prawn/security.rb +59 -40
  50. data/lib/prawn/security/arcfour.rb +52 -0
  51. data/lib/prawn/soft_mask.rb +4 -4
  52. data/lib/prawn/stamp.rb +5 -3
  53. data/lib/prawn/table.rb +83 -60
  54. data/lib/prawn/table/cell.rb +17 -21
  55. data/lib/prawn/table/cell/image.rb +2 -3
  56. data/lib/prawn/table/cell/in_table.rb +8 -2
  57. data/lib/prawn/table/cell/span_dummy.rb +5 -0
  58. data/lib/prawn/table/cell/subtable.rb +3 -2
  59. data/lib/prawn/table/cell/text.rb +14 -12
  60. data/lib/prawn/table/cells.rb +58 -14
  61. data/lib/prawn/table/column_width_calculator.rb +61 -0
  62. data/lib/prawn/text.rb +27 -26
  63. data/lib/prawn/text/box.rb +12 -6
  64. data/lib/prawn/text/formatted.rb +5 -4
  65. data/lib/prawn/text/formatted/arranger.rb +290 -0
  66. data/lib/prawn/text/formatted/box.rb +85 -57
  67. data/lib/prawn/text/formatted/fragment.rb +11 -11
  68. data/lib/prawn/text/formatted/line_wrap.rb +266 -0
  69. data/lib/prawn/text/formatted/parser.rb +11 -4
  70. data/lib/prawn/text/formatted/wrap.rb +156 -0
  71. data/lib/prawn/utilities.rb +5 -3
  72. data/manual/document_and_page_options/document_and_page_options.rb +2 -1
  73. data/manual/document_and_page_options/metadata.rb +3 -3
  74. data/manual/document_and_page_options/page_size.rb +2 -2
  75. data/manual/document_and_page_options/print_scaling.rb +20 -0
  76. data/manual/example_file.rb +2 -7
  77. data/manual/example_helper.rb +62 -81
  78. data/manual/graphics/common_lines.rb +2 -0
  79. data/manual/graphics/helper.rb +11 -4
  80. data/manual/graphics/stroke_dash.rb +19 -14
  81. data/manual/manual/cover.rb +16 -0
  82. data/manual/manual/manual.rb +1 -5
  83. data/manual/text/fallback_fonts.rb +4 -4
  84. data/manual/text/formatted_text.rb +5 -5
  85. data/manual/text/inline.rb +2 -4
  86. data/manual/text/registering_families.rb +12 -12
  87. data/manual/text/single_usage.rb +4 -4
  88. data/manual/text/text.rb +0 -2
  89. data/prawn.gemspec +21 -13
  90. data/spec/acceptance/png.rb +23 -0
  91. data/spec/annotations_spec.rb +16 -32
  92. data/spec/bounding_box_spec.rb +22 -5
  93. data/spec/cell_spec.rb +49 -5
  94. data/spec/column_box_spec.rb +32 -0
  95. data/spec/destinations_spec.rb +5 -5
  96. data/spec/document_spec.rb +112 -118
  97. data/spec/extensions/encoding_helpers.rb +5 -2
  98. data/spec/font_metric_cache_spec.rb +52 -0
  99. data/spec/font_spec.rb +121 -120
  100. data/spec/formatted_text_arranger_spec.rb +24 -24
  101. data/spec/formatted_text_box_spec.rb +31 -32
  102. data/spec/formatted_text_fragment_spec.rb +2 -2
  103. data/spec/graphics_spec.rb +63 -45
  104. data/spec/grid_spec.rb +24 -13
  105. data/spec/image_handler_spec.rb +54 -0
  106. data/spec/images_spec.rb +34 -21
  107. data/spec/inline_formatted_text_parser_spec.rb +69 -20
  108. data/spec/jpg_spec.rb +3 -3
  109. data/spec/line_wrap_spec.rb +25 -14
  110. data/spec/measurement_units_spec.rb +5 -5
  111. data/spec/outline_spec.rb +68 -64
  112. data/spec/png_spec.rb +15 -18
  113. data/spec/reference_spec.rb +2 -82
  114. data/spec/repeater_spec.rb +1 -1
  115. data/spec/security_spec.rb +41 -9
  116. data/spec/soft_mask_spec.rb +0 -40
  117. data/spec/span_spec.rb +6 -11
  118. data/spec/spec_helper.rb +20 -2
  119. data/spec/stamp_spec.rb +19 -20
  120. data/spec/stroke_styles_spec.rb +31 -13
  121. data/spec/table/span_dummy_spec.rb +17 -0
  122. data/spec/table_spec.rb +268 -43
  123. data/spec/text_at_spec.rb +13 -27
  124. data/spec/text_box_spec.rb +35 -30
  125. data/spec/text_spec.rb +56 -40
  126. data/spec/transparency_spec.rb +5 -5
  127. metadata +214 -217
  128. data/README.md +0 -98
  129. data/data/fonts/Action Man.dfont +0 -0
  130. data/data/fonts/Activa.ttf +0 -0
  131. data/data/fonts/Chalkboard.ttf +0 -0
  132. data/data/fonts/DejaVuSans.ttf +0 -0
  133. data/data/fonts/Dustismo_Roman.ttf +0 -0
  134. data/data/fonts/comicsans.ttf +0 -0
  135. data/data/fonts/gkai00mp.ttf +0 -0
  136. data/data/images/16bit.dat +0 -0
  137. data/data/images/barcode_issue.png +0 -0
  138. data/data/images/dice.dat +0 -0
  139. data/data/images/page_white_text.dat +0 -0
  140. data/data/images/rails.dat +0 -0
  141. data/data/images/rails.png +0 -0
  142. data/lib/prawn/compatibility.rb +0 -87
  143. data/lib/prawn/core.rb +0 -87
  144. data/lib/prawn/core/annotations.rb +0 -61
  145. data/lib/prawn/core/byte_string.rb +0 -9
  146. data/lib/prawn/core/destinations.rb +0 -90
  147. data/lib/prawn/core/document_state.rb +0 -79
  148. data/lib/prawn/core/literal_string.rb +0 -16
  149. data/lib/prawn/core/name_tree.rb +0 -177
  150. data/lib/prawn/core/object_store.rb +0 -320
  151. data/lib/prawn/core/page.rb +0 -212
  152. data/lib/prawn/core/pdf_object.rb +0 -125
  153. data/lib/prawn/core/reference.rb +0 -119
  154. data/lib/prawn/core/text.rb +0 -268
  155. data/lib/prawn/core/text/formatted/arranger.rb +0 -294
  156. data/lib/prawn/core/text/formatted/line_wrap.rb +0 -288
  157. data/lib/prawn/core/text/formatted/wrap.rb +0 -153
  158. data/lib/prawn/document/page_geometry.rb +0 -136
  159. data/lib/prawn/document/snapshot.rb +0 -89
  160. data/manual/manual/foreword.rb +0 -13
  161. data/manual/templates/full_template.rb +0 -23
  162. data/manual/templates/page_template.rb +0 -47
  163. data/manual/templates/templates.rb +0 -26
  164. data/manual/text/group.rb +0 -29
  165. data/spec/name_tree_spec.rb +0 -112
  166. data/spec/object_store_spec.rb +0 -170
  167. data/spec/pdf_object_spec.rb +0 -172
  168. data/spec/snapshot_spec.rb +0 -186
  169. data/spec/template_spec.rb +0 -351
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: edf9e637f24e5c4554e995712cb589f0b21737fb
4
+ data.tar.gz: 97750f73864c853ff874f8a5a0f7984a6f9d8279
5
+ SHA512:
6
+ metadata.gz: bd80b65ac0360fa6786b6bffacfc34a87511cc8d79e260dfd8db78b86a5003182a41d5ad559e5c1403724273c83b71b29d426c31a422fd7b1e5986a859ac1a5d
7
+ data.tar.gz: 4b63fc53c8481155ed173cb3e4b8146ac052173e0bd91f4fa27aece66525ad5f6968a48230addbb5ae2a043a3bc33829c79c9447a8c734f3bd2da45468b913da
@@ -0,0 +1,9 @@
1
+ --charset UTF-8
2
+ --main README.md
3
+ --title 'Prawn Documentation'
4
+ --no-private
5
+ -
6
+ CONTRIBUTING.md
7
+ COPYING
8
+ LICENSE
9
+ README.md
data/COPYING CHANGED
@@ -1,2 +1,2 @@
1
- Prawn may be used under Matz's terms for Ruby, or GPLv2 or GPLv3. See LICENSE
2
- for Matz's terms, or GPLv2 and GPLv3 files.
1
+ Prawn may be used under Matz's original licensing terms for Ruby, or GPLv2 or GPLv3.
2
+ See LICENSE for Matz's terms, or GPLv2 and GPLv3 files.
data/Gemfile CHANGED
@@ -1,18 +1,11 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
 
3
- gem "ttfunk", "~>1.0.3"
4
- gem "pdf-reader", "~> 1.2"
5
- gem "ruby-rc4"
6
- gem "afm"
3
+ gemspec
7
4
 
8
- group :development do
9
- gem "coderay", "~> 1.0.7"
10
- gem "rdoc"
11
- end
12
-
13
- group :test do
14
- gem "pdf-inspector", "~> 1.0.2", :require => "pdf/inspector"
15
- gem "rspec"
16
- gem "mocha", :require => false
17
- gem "rake"
5
+ if ENV["CI"]
6
+ platforms :rbx do
7
+ gem "rubysl-singleton", "~> 2.0"
8
+ gem "rubysl-digest", "~> 2.0"
9
+ gem "rubysl-enumerator", "~> 2.0"
10
+ end
18
11
  end
data/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
1
  Prawn is copyrighted free software produced by Gregory Brown along with
2
2
  community contributions. See git log for authorship information.
3
3
 
4
- Licensing terms follow (License of Ruby):
4
+ Licensing terms follow:
5
5
 
6
6
  You can redistribute Prawn and/or modify it under either the terms of the GPLv2
7
7
  or GPLv3 (see GPLv2 and GPLv3 files), or the conditions below:
data/Rakefile CHANGED
@@ -3,32 +3,29 @@ Bundler.setup
3
3
 
4
4
  require 'rake'
5
5
  require 'rspec/core/rake_task'
6
- require 'rdoc/task'
6
+ require 'yard'
7
7
  require 'rubygems/package_task'
8
8
 
9
9
  task :default => [:spec]
10
-
10
+
11
11
  desc "Run all rspec files"
12
- RSpec::Core::RakeTask.new("spec")
12
+ RSpec::Core::RakeTask.new("spec") do |c|
13
+ c.rspec_opts = "-t ~unresolved"
14
+ end
13
15
 
14
16
  desc "Show library's code statistics"
15
17
  task :stats do
16
- require 'code_statistics'
17
- CodeStatistics::TEST_TYPES << "Specs"
18
- CodeStatistics.new( ["Prawn", "lib"],
19
- ["Specs", "spec"] ).to_s
18
+ require 'code_statistics'
19
+ CodeStatistics::TEST_TYPES << "Specs"
20
+ CodeStatistics.new( ["Prawn", "lib"],
21
+ ["Specs", "spec"] ).to_s
20
22
  end
21
23
 
22
- desc "genrates documentation"
23
- RDoc::Task.new do |rdoc|
24
- rdoc.rdoc_files.include( "README",
25
- "COPYING",
26
- "LICENSE",
27
- "HACKING", "lib/" )
28
- rdoc.main = "README"
29
- rdoc.rdoc_dir = "doc/html"
30
- rdoc.title = "Prawn Documentation"
24
+ YARD::Rake::YardocTask.new do |t|
25
+ t.options = ['--output-dir', 'doc/html']
31
26
  end
27
+ task :docs => :yard
28
+
32
29
 
33
30
  desc "Generate the 'Prawn by Example' manual"
34
31
  task :manual do
@@ -43,3 +40,15 @@ Gem::PackageTask.new(spec) do |pkg|
43
40
  pkg.need_zip = true
44
41
  pkg.need_tar = true
45
42
  end
43
+
44
+ desc "Run a console with Prawn loaded"
45
+ task :console do
46
+ require 'irb'
47
+ require 'irb/completion'
48
+ require_relative 'lib/prawn'
49
+ Prawn.debug = true
50
+
51
+ ARGV.clear
52
+ IRB.start
53
+ end
54
+
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ All images distributed with Prawn need to be freely distributable under
2
+ a license that is compatible with our own (see LICENSE and COPYING files).
3
+
4
+ It is our understanding that all files in this folder are compatible
5
+ with our licensing, but if you notice any problems, please
6
+ file an issue in our tracker on Github and we will promptly address it:
7
+
8
+ https://github.com/prawnpdf/prawn/issues
@@ -1,29 +1,91 @@
1
1
  # Welcome to Prawn, the best PDF Generation library ever.
2
2
  # This documentation covers user level functionality.
3
3
  #
4
- # Those looking to contribute code or write extensions should look
5
- # into the lib/prawn/core/* source tree.
6
- #
7
- module Prawn #:nodoc:
8
- VERSION = "1.0.0.rc2"
4
+ require "set"
5
+
6
+ require 'ttfunk'
7
+ require "pdf/core"
8
+
9
+ module Prawn
10
+ VERSION = "1.0.0"
11
+
12
+ extend self
13
+
14
+ file = __FILE__
15
+ file = File.readlink(file) if File.symlink?(file)
16
+ dir = File.dirname(file)
17
+
18
+ # The base source directory for Prawn as installed on the system
19
+ #
20
+ #
21
+ BASEDIR = File.expand_path(File.join(dir, '..'))
22
+ DATADIR = File.expand_path(File.join(dir, '..', 'data'))
23
+
24
+ FLOAT_PRECISION = 1.0e-9
25
+
26
+ # Whe set to true, Prawn will verify hash options to ensure only valid keys
27
+ # are used. Off by default.
28
+ #
29
+ # Example:
30
+ # >> Prawn::Document.new(:tomato => "Juicy")
31
+ # Prawn::Errors::UnknownOption:
32
+ # Detected unknown option(s): [:tomato]
33
+ # Accepted options are: [:page_size, :page_layout, :left_margin, ...]
34
+ #
35
+ attr_accessor :debug # @private
36
+
37
+ def verify_options(accepted, actual) # @private
38
+ return unless debug || $DEBUG
39
+ unless (act=Set[*actual.keys]).subset?(acc=Set[*accepted])
40
+ raise Prawn::Errors::UnknownOption,
41
+ "\nDetected unknown option(s): #{(act - acc).to_a.inspect}\n" <<
42
+ "Accepted options are: #{accepted.inspect}"
43
+ end
44
+ yield if block_given?
45
+ end
46
+
47
+ module Configurable # @private
48
+ def configuration(*args)
49
+ @config ||= Marshal.load(Marshal.dump(default_configuration))
50
+ if Hash === args[0]
51
+ @config.update(args[0])
52
+ elsif args.length > 1
53
+ @config.values_at(*args)
54
+ elsif args.length == 1
55
+ @config[args[0]]
56
+ else
57
+ @config
58
+ end
59
+ end
60
+
61
+ alias_method :C, :configuration
62
+ end
9
63
  end
10
64
 
11
- require "prawn/utilities"
12
- require "prawn/core"
13
- require "prawn/text"
14
- require "prawn/graphics"
15
- require "prawn/images"
16
- require "prawn/images/image"
17
- require "prawn/images/jpg"
18
- require "prawn/images/png"
19
- require "prawn/stamp"
20
- require "prawn/soft_mask"
21
- require "prawn/security"
22
- require "prawn/document"
23
- require "prawn/font"
24
- require "prawn/encoding"
25
- require "prawn/measurements"
26
- require "prawn/repeater"
27
- require "prawn/outline"
28
- require "prawn/layout"
65
+ require_relative "prawn/errors"
66
+
67
+
68
+ require_relative "prawn/utilities"
69
+ require_relative "prawn/text"
70
+ require_relative "prawn/graphics"
71
+ require_relative "prawn/images"
72
+ require_relative "prawn/images/image"
73
+ require_relative "prawn/images/jpg"
74
+ require_relative "prawn/images/png"
75
+ require_relative "prawn/stamp"
76
+ require_relative "prawn/soft_mask"
77
+ require_relative "prawn/security"
78
+ require_relative "prawn/document"
79
+ require_relative "prawn/font"
80
+ require_relative "prawn/encoding"
81
+ require_relative "prawn/measurements"
82
+ require_relative "prawn/repeater"
83
+ require_relative "prawn/outline"
84
+ require_relative "prawn/layout"
85
+
86
+ require_relative "prawn/image_handler"
87
+
88
+
29
89
 
90
+ Prawn.image_handler.register(Prawn::Images::PNG)
91
+ Prawn.image_handler.register(Prawn::Images::JPG)
@@ -7,13 +7,12 @@
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
9
  require "stringio"
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"
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/graphics_state"
17
16
 
18
17
  module Prawn
19
18
 
@@ -52,9 +51,8 @@ module Prawn
52
51
  #
53
52
  class Document
54
53
  include Prawn::Document::Internals
55
- include Prawn::Core::Annotations
56
- include Prawn::Core::Destinations
57
- include Prawn::Document::Snapshot
54
+ include PDF::Core::Annotations
55
+ include PDF::Core::Destinations
58
56
  include Prawn::Document::GraphicsState
59
57
  include Prawn::Document::Security
60
58
  include Prawn::Text
@@ -63,6 +61,16 @@ module Prawn
63
61
  include Prawn::Stamp
64
62
  include Prawn::SoftMask
65
63
 
64
+ # @group Extension API
65
+
66
+ # NOTE: We probably need to rethink the options validation system, but this
67
+ # constant temporarily allows for extensions to modify the list.
68
+
69
+ VALID_OPTIONS = [:page_size, :page_layout, :margin, :left_margin,
70
+ :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
71
+ :compress, :skip_encoding, :background, :info,
72
+ :text_formatter, :print_scaling]
73
+
66
74
  # Any module added to this array will be included into instances of
67
75
  # Prawn::Document at the per-object level. These will also be inherited by
68
76
  # any subclasses.
@@ -83,14 +91,28 @@ module Prawn
83
91
  # party!
84
92
  # end
85
93
  #
94
+ #
86
95
  def self.extensions
87
96
  @extensions ||= []
88
97
  end
89
98
 
90
- def self.inherited(base) #:nodoc:
99
+ # @private
100
+ def self.inherited(base)
91
101
  extensions.each { |e| base.extensions << e }
92
102
  end
93
103
 
104
+ # @group Stable Attributes
105
+
106
+ attr_accessor :margin_box
107
+ attr_reader :margins, :y
108
+ attr_accessor :page_number
109
+
110
+ # @group Extension Attributes
111
+
112
+ attr_accessor :text_formatter
113
+
114
+ # @group Stable API
115
+
94
116
  # Creates and renders a PDF document.
95
117
  #
96
118
  # When using the implicit block form, Prawn will evaluate the block
@@ -135,11 +157,10 @@ module Prawn
135
157
  # <tt>:bottom_margin</tt>:: Sets the bottom margin in points [0.5 inch]
136
158
  # <tt>:skip_page_creation</tt>:: Creates a document without starting the first page [false]
137
159
  # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
138
- # <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
139
160
  # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
140
161
  # <tt>:background_scale</tt>:: Backgound image scale [1] [nil]
141
162
  # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
142
- # <tt>:template</tt>:: The path to an existing PDF file to use as a template [nil]
163
+ # <tt>:text_formatter</tt>: The text formatter to use for <tt>:inline_format</tt>ted text [Prawn::Text::Formatted::Parser]
143
164
  #
144
165
  # Setting e.g. the :margin to 100 points and the :left_margin to 50 will result in margins
145
166
  # of 100 points on every side except for the left, where it will be 50.
@@ -173,19 +194,18 @@ module Prawn
173
194
  def initialize(options={},&block)
174
195
  options = options.dup
175
196
 
176
- Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
177
- :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
178
- :compress, :skip_encoding, :background, :info,
179
- :optimize_objects, :template], options
197
+ Prawn.verify_options VALID_OPTIONS, options
180
198
 
181
199
  # need to fix, as the refactoring breaks this
182
200
  # raise NotImplementedError if options[:skip_page_creation]
183
201
 
184
202
  self.class.extensions.reverse_each { |e| extend e }
185
- @internal_state = Prawn::Core::DocumentState.new(options)
203
+ @internal_state = PDF::Core::DocumentState.new(options)
186
204
  @internal_state.populate_pages_from_store(self)
187
205
  min_version(state.store.min_version) if state.store.min_version
188
206
 
207
+ min_version(1.6) if options[:print_scaling] == :none
208
+
189
209
  @background = options[:background]
190
210
  @background_scale = options[:background_scale] || 1
191
211
  @font_size = 12
@@ -195,19 +215,12 @@ module Prawn
195
215
 
196
216
  @page_number = 0
197
217
 
218
+ @text_formatter = options.delete(:text_formatter) || Text::Formatted::Parser
219
+
198
220
  options[:size] = options.delete(:page_size)
199
221
  options[:layout] = options.delete(:page_layout)
200
222
 
201
- if options[:template]
202
- fresh_content_streams(options)
203
- go_to_page(1)
204
- else
205
- if options[:skip_page_creation] || options[:template]
206
- start_new_page(options.merge(:orphan => true))
207
- else
208
- start_new_page(options)
209
- end
210
- end
223
+ initialize_first_page(options)
211
224
 
212
225
  @bounding_box = @margin_box
213
226
 
@@ -216,18 +229,7 @@ module Prawn
216
229
  end
217
230
  end
218
231
 
219
- attr_accessor :margin_box
220
- attr_reader :margins, :y
221
- attr_writer :font_size
222
- attr_accessor :page_number
223
-
224
- def state
225
- @internal_state
226
- end
227
-
228
- def page
229
- state.page
230
- end
232
+ # @group Stable API
231
233
 
232
234
  # Creates and advances to a new page in the document.
233
235
  #
@@ -239,14 +241,6 @@ module Prawn
239
241
  # pdf.start_new_page(:left_margin => 50, :right_margin => 50)
240
242
  # pdf.start_new_page(:margin => 100)
241
243
  #
242
- # A template for a page can be specified by pointing to the path of and existing pdf.
243
- # One can also specify which page of the template which defaults otherwise to 1.
244
- #
245
- # pdf.start_new_page(:template => multipage_template.pdf, :template_page => 2)
246
- #
247
- # Note: templates get indexed by either the object_id of the filename or stream
248
- # entered so that if you reuse the same template multiple times be sure to use the
249
- # same instance for more efficient use of resources and smaller rendered pdfs.
250
244
  def start_new_page(options = {})
251
245
  if last_page = state.page
252
246
  last_page_size = last_page.size
@@ -258,14 +252,13 @@ module Prawn
258
252
  :layout => options[:layout] || last_page_layout,
259
253
  :margins => last_page_margins}
260
254
  if last_page
261
- new_graphic_state = last_page.graphic_state.dup
255
+ new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
262
256
  #erase the color space so that it gets reset on new page for fussy pdf-readers
263
- new_graphic_state.color_space = {}
257
+ new_graphic_state.color_space = {} if new_graphic_state
264
258
  page_options.merge!(:graphic_state => new_graphic_state)
265
259
  end
266
- merge_template_options(page_options, options) if options[:template]
267
260
 
268
- state.page = Prawn::Core::Page.new(self, page_options)
261
+ state.page = PDF::Core::Page.new(self, page_options)
269
262
 
270
263
  apply_margin_options(options)
271
264
  generate_margin_box
@@ -276,8 +269,7 @@ module Prawn
276
269
  @bounding_box = @margin_box
277
270
  end
278
271
 
279
- state.page.new_content_stream if options[:template]
280
- use_graphic_settings(options[:template])
272
+ use_graphic_settings
281
273
 
282
274
  unless options[:orphan]
283
275
  state.insert_page(state.page, @page_number)
@@ -354,19 +346,26 @@ module Prawn
354
346
  self.y = original_y
355
347
  end
356
348
 
357
- # Renders the PDF document to string
349
+ # Renders the PDF document to string.
350
+ # Pass an open file descriptor to render to file.
358
351
  #
359
- def render
360
- output = StringIO.new
352
+ def render(output = StringIO.new)
353
+ if output.instance_of?(StringIO)
354
+ output.set_encoding(::Encoding::ASCII_8BIT)
355
+ end
361
356
  finalize_all_page_contents
362
357
 
363
358
  render_header(output)
364
359
  render_body(output)
365
360
  render_xref(output)
366
361
  render_trailer(output)
367
- str = output.string
368
- str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
369
- str
362
+ if output.instance_of?(StringIO)
363
+ str = output.string
364
+ str.force_encoding(::Encoding::ASCII_8BIT)
365
+ return str
366
+ else
367
+ return nil
368
+ end
370
369
  end
371
370
 
372
371
  # Renders the PDF document to file.
@@ -374,8 +373,7 @@ module Prawn
374
373
  # pdf.render_file "foo.pdf"
375
374
  #
376
375
  def render_file(filename)
377
- Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
378
- File.open(filename,mode) { |f| f << render }
376
+ File.open(filename, "wb") { |f| render(f) }
379
377
  end
380
378
 
381
379
  # The bounds method returns the current bounding box you are currently in,
@@ -411,6 +409,7 @@ module Prawn
411
409
 
412
410
  # Returns the innermost non-stretchy bounding box.
413
411
  #
412
+ # @private
414
413
  def reference_bounds
415
414
  @bounding_box.reference_bounds
416
415
  end
@@ -496,47 +495,6 @@ module Prawn
496
495
  bounds.indent(left, right, &block)
497
496
  end
498
497
 
499
-
500
- def mask(*fields) # :nodoc:
501
- # Stores the current state of the named attributes, executes the block, and
502
- # then restores the original values after the block has executed.
503
- # -- I will remove the nodoc if/when this feature is a little less hacky
504
- stored = {}
505
- fields.each { |f| stored[f] = send(f) }
506
- yield
507
- fields.each { |f| send("#{f}=", stored[f]) }
508
- end
509
-
510
- # Attempts to group the given block vertically within the current context.
511
- # First attempts to render it in the current position on the current page.
512
- # If that attempt overflows, it is tried anew after starting a new context
513
- # (page or column). Returns a logically true value if the content fits in
514
- # one page/column, false if a new page or column was needed.
515
- #
516
- # Raises CannotGroup if the provided content is too large to fit alone in
517
- # the current page or column.
518
- #
519
- def group(second_attempt=false)
520
- old_bounding_box = @bounding_box
521
- @bounding_box = SimpleDelegator.new(@bounding_box)
522
-
523
- def @bounding_box.move_past_bottom
524
- raise RollbackTransaction
525
- end
526
-
527
- success = transaction { yield }
528
-
529
- @bounding_box = old_bounding_box
530
-
531
- unless success
532
- raise Prawn::Errors::CannotGroup if second_attempt
533
- old_bounding_box.move_past_bottom
534
- group(second_attempt=true) { yield }
535
- end
536
-
537
- success
538
- end
539
-
540
498
  # Places a text box on specified pages for page numbering. This should be called
541
499
  # towards the end of document creation, after all your content is already in
542
500
  # place. In your template string, <page> refers to the current page, and
@@ -609,6 +567,42 @@ module Prawn
609
567
  end
610
568
  end
611
569
 
570
+ # Returns true if content streams will be compressed before rendering,
571
+ # false otherwise
572
+ #
573
+ def compression_enabled?
574
+ !!state.compress
575
+ end
576
+
577
+ # @group Experimental API
578
+
579
+ # Attempts to group the given block vertically within the current context.
580
+ # First attempts to render it in the current position on the current page.
581
+ # If that attempt overflows, it is tried anew after starting a new context
582
+ # (page or column). Returns a logically true value if the content fits in
583
+ # one page/column, false if a new page or column was needed.
584
+ #
585
+ # Raises CannotGroup if the provided content is too large to fit alone in
586
+ # the current page or column.
587
+ #
588
+ # @private
589
+ def group(*a, &b)
590
+ raise NotImplementedError,
591
+ "Document#group has been disabled because its implementation "+
592
+ "lead to corrupted documents whenever a page boundary was "+
593
+ "crossed. We will try to work on reimplementing it in a "+
594
+ "future release"
595
+ end
596
+
597
+ # @private
598
+ def transaction
599
+ raise NotImplementedError,
600
+ "Document#transaction has been disabled because its implementation "+
601
+ "lead to corrupted documents whenever a page boundary was "+
602
+ "crossed. We will try to work on reimplementing it in a "+
603
+ "future release"
604
+ end
605
+
612
606
  # Provides a way to execute a block of code repeatedly based on a
613
607
  # page_filter.
614
608
  #
@@ -634,23 +628,45 @@ module Prawn
634
628
  end
635
629
  end
636
630
 
631
+ # @private
632
+
633
+ def mask(*fields)
634
+ # Stores the current state of the named attributes, executes the block, and
635
+ # then restores the original values after the block has executed.
636
+ # -- I will remove the nodoc if/when this feature is a little less hacky
637
+ stored = {}
638
+ fields.each { |f| stored[f] = send(f) }
639
+ yield
640
+ fields.each { |f| send("#{f}=", stored[f]) }
641
+ end
637
642
 
638
- # Returns true if content streams will be compressed before rendering,
639
- # false otherwise
640
- #
641
- def compression_enabled?
642
- !!state.compress
643
+ # @group Extension API
644
+
645
+ def initialize_first_page(options)
646
+ if options[:skip_page_creation]
647
+ start_new_page(options.merge(:orphan => true))
648
+ else
649
+ start_new_page(options)
650
+ end
643
651
  end
644
652
 
645
- private
653
+ ## Internals. Don't depend on them!
646
654
 
647
- def merge_template_options(page_options, options)
648
- object_id = state.store.import_page(options[:template], options[:template_page] || 1)
649
- page_options.merge!(:object_id => object_id, :page_template => true)
655
+ # @private
656
+ def state
657
+ @internal_state
650
658
  end
651
659
 
660
+ # @private
661
+ def page
662
+ state.page
663
+ end
664
+
665
+ private
666
+
667
+
652
668
  # setting override_settings to true ensures that a new graphic state does not end up using
653
- # previous settings especially from imported template streams
669
+ # previous settings.
654
670
  def use_graphic_settings(override_settings = false)
655
671
  set_fill_color if current_fill_color != "000000" || override_settings
656
672
  set_stroke_color if current_stroke_color != "000000" || override_settings
@@ -680,9 +696,7 @@ module Prawn
680
696
 
681
697
  # we must update bounding box if not flowing from the previous page
682
698
  #
683
- # FIXME: This may have a bug where the old margin is restored
684
- # when the bounding box exits.
685
- @bounding_box = @margin_box if old_margin_box == @bounding_box
699
+ @bounding_box = @margin_box unless @bounding_box && @bounding_box.parent
686
700
  end
687
701
 
688
702
  def apply_margin_options(options)
@@ -703,5 +717,9 @@ module Prawn
703
717
  end
704
718
  end
705
719
  end
720
+
721
+ def font_metric_cache #:nodoc:
722
+ @font_metric_cache ||= FontMetricCache.new( self )
723
+ end
706
724
  end
707
725
  end