prawn 1.0.0.rc2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -10,6 +10,8 @@ require 'date'
10
10
  module Prawn
11
11
  class Document
12
12
 
13
+ # @group Experimental API
14
+
13
15
  # Instantiates and draws a cell on the document.
14
16
  #
15
17
  # cell(:content => "Hello world!", :at => [12, 34])
@@ -122,7 +124,7 @@ module Prawn
122
124
  # HTML RGB-format ("ccffff") border colors: [top, right, bottom, left].
123
125
  #
124
126
  attr_reader :border_colors
125
-
127
+
126
128
  # Line style
127
129
  #
128
130
  attr_reader :border_lines
@@ -151,7 +153,7 @@ module Prawn
151
153
  # this span group. They know their own width / height, but do not draw
152
154
  # anything.
153
155
  #
154
- attr_reader :dummy_cells # :nodoc:
156
+ attr_reader :dummy_cells
155
157
 
156
158
  # Instantiates a Cell based on the given options. The particular class of
157
159
  # cell returned depends on the :content argument. See the Prawn::Table
@@ -163,7 +165,7 @@ module Prawn
163
165
  content.kind_of?(Date)
164
166
 
165
167
  if content.is_a?(Hash)
166
- if img = content[:image]
168
+ if content[:image]
167
169
  return Cell::Image.new(pdf, at, content)
168
170
  end
169
171
  options.update(content)
@@ -232,7 +234,9 @@ module Prawn
232
234
  # cell.border_width = 2
233
235
  #
234
236
  def style(options={}, &block)
235
- options.each { |k, v| send("#{k}=", v) }
237
+ options.each do |k, v|
238
+ send("#{k}=", v) if respond_to?("#{k}=")
239
+ end
236
240
 
237
241
  # The block form supports running a single block for multiple cells, as
238
242
  # in Cells#style.
@@ -245,7 +249,7 @@ module Prawn
245
249
  def width_ignoring_span
246
250
  # We can't ||= here because the FP error accumulates on the round-trip
247
251
  # from #content_width.
248
- @width || (content_width + padding_left + padding_right)
252
+ defined?(@width) && @width || (content_width + padding_left + padding_right)
249
253
  end
250
254
 
251
255
  # Returns the cell's width in points, inclusive of padding. If the cell is
@@ -275,7 +279,7 @@ module Prawn
275
279
  # Returns the width of the bare content in the cell, excluding padding.
276
280
  #
277
281
  def content_width
278
- if @width # manually set
282
+ if defined?(@width) && @width # manually set
279
283
  return @width - padding_left - padding_right
280
284
  end
281
285
 
@@ -302,7 +306,7 @@ module Prawn
302
306
  def height_ignoring_span
303
307
  # We can't ||= here because the FP error accumulates on the round-trip
304
308
  # from #content_height.
305
- @height || (content_height + padding_top + padding_bottom)
309
+ defined?(@height) && @height || (content_height + padding_top + padding_bottom)
306
310
  end
307
311
 
308
312
  # Returns the cell's height in points, inclusive of padding. If the cell
@@ -325,7 +329,7 @@ module Prawn
325
329
  # Returns the height of the bare content in the cell, excluding padding.
326
330
  #
327
331
  def content_height
328
- if @height # manually set
332
+ if defined?(@height) && @height # manually set
329
333
  return @height - padding_top - padding_bottom
330
334
  end
331
335
 
@@ -359,7 +363,7 @@ module Prawn
359
363
  # pdf.table([["foo", "bar"]]) { cells[0, 1].colspan = 2 }
360
364
  #
361
365
  def colspan=(span)
362
- if @initializer_run
366
+ if defined?(@initializer_run) && @initializer_run
363
367
  raise Prawn::Errors::InvalidTableSpan,
364
368
  "colspan must be provided in the table's structure, never in the " +
365
369
  "initialization block. See Prawn's documentation for details."
@@ -380,7 +384,7 @@ module Prawn
380
384
  # pdf.table([["foo", "bar"], ["baz"]]) { cells[0, 1].rowspan = 2 }
381
385
  #
382
386
  def rowspan=(span)
383
- if @initializer_run
387
+ if defined?(@initializer_run) && @initializer_run
384
388
  raise Prawn::Errors::InvalidTableSpan,
385
389
  "rowspan must be provided in the table's structure, never in the " +
386
390
  "initialization block. See Prawn's documentation for details."
@@ -543,14 +547,6 @@ module Prawn
543
547
  @border_colors[0] = val
544
548
  end
545
549
 
546
- def border_top_color
547
- @border_colors[0]
548
- end
549
-
550
- def border_top_color=(val)
551
- @border_colors[0] = val
552
- end
553
-
554
550
  def border_right_color
555
551
  @border_colors[1]
556
552
  end
@@ -640,7 +636,7 @@ module Prawn
640
636
  @min_width ||= padding_left + padding_right
641
637
  @max_width ||= @pdf.bounds.width
642
638
  end
643
-
639
+
644
640
  # Sets border line style on this cell. The argument can be one of:
645
641
  #
646
642
  # Possible values are: :solid, :dashed, :dotted
@@ -704,7 +700,7 @@ module Prawn
704
700
  # Draws the cell's background color.
705
701
  #
706
702
  def draw_background(pt)
707
- if @background_color
703
+ if defined?(@background_color) && @background_color
708
704
  @pdf.mask(:fill_color) do
709
705
  @pdf.fill_color @background_color
710
706
  @pdf.fill_rectangle pt, width, height
@@ -755,7 +751,7 @@ module Prawn
755
751
  raise ArgumentError, "border_line must be :solid, :dotted or" +
756
752
  " :dashed"
757
753
  end
758
-
754
+
759
755
  @pdf.line_width = border_width
760
756
  @pdf.stroke_color = border_color
761
757
  @pdf.stroke_line(from, to)
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # image.rb: Table image cells.
4
4
  #
@@ -9,8 +9,7 @@ module Prawn
9
9
  class Table
10
10
  class Cell
11
11
 
12
- # A Cell that contains another table.
13
- #
12
+ # @private
14
13
  class Image < Cell
15
14
 
16
15
  def initialize(pdf, point, options={})
@@ -1,21 +1,27 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  # Accessors for using a Cell inside a Table.
4
+ #
5
+ # Contributed by Brad Ediger.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
4
8
 
5
9
  module Prawn
6
- class Table
10
+ class Table
11
+
7
12
  class Cell
8
13
 
9
14
  # This module extends Cell objects when they are used in a table (as
10
15
  # opposed to standalone). Its properties apply to cells-in-tables but not
11
16
  # cells themselves.
12
17
  #
18
+ # @private
13
19
  module InTable
14
20
 
15
21
  # Row number (0-based).
16
22
  #
17
23
  attr_accessor :row
18
-
24
+
19
25
  # Column number (0-based).
20
26
  #
21
27
  attr_accessor :column
@@ -12,6 +12,7 @@ module Prawn
12
12
  # A Cell object used to represent all but the topmost cell in a span
13
13
  # group.
14
14
  #
15
+ # @private
15
16
  class SpanDummy < Cell
16
17
  def initialize(pdf, master_cell)
17
18
  super(pdf, [0, pdf.cursor])
@@ -69,6 +70,10 @@ module Prawn
69
70
  @master_cell.border_bottom_width = val if bottommost?
70
71
  end
71
72
 
73
+ def background_color
74
+ @master_cell.background_color
75
+ end
76
+
72
77
  private
73
78
 
74
79
  # Are we on the right border of the span?
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # subtable.rb: Yo dawg.
4
4
  #
@@ -11,6 +11,7 @@ module Prawn
11
11
 
12
12
  # A Cell that contains another table.
13
13
  #
14
+ # @private
14
15
  class Subtable < Cell
15
16
 
16
17
  attr_reader :subtable
@@ -47,7 +48,7 @@ module Prawn
47
48
  @subtable.cells.max_width
48
49
  end
49
50
 
50
- # Proxied to subtable.
51
+ # Proxied to subtable.
51
52
  #
52
53
  def natural_content_height
53
54
  @subtable.cells.height
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # text.rb: Text table cells.
4
4
  #
@@ -12,6 +12,7 @@ module Prawn
12
12
  # A Cell that contains text. Has some limited options to set font family,
13
13
  # size, and style.
14
14
  #
15
+ # @private
15
16
  class Text < Cell
16
17
 
17
18
  TextOptions = [:inline_format, :kerning, :size, :align, :valign,
@@ -64,7 +65,7 @@ module Prawn
64
65
  # Draws the text content into its bounding box.
65
66
  #
66
67
  def draw_content
67
- with_font do
68
+ with_font do
68
69
  @pdf.move_down((@pdf.font.line_gap + @pdf.font.descender)/2)
69
70
  with_text_color do
70
71
  text_box(:width => spanned_content_width + FPTolerance,
@@ -78,7 +79,7 @@ module Prawn
78
79
  # Sets a reasonable minimum width. If the cell has any content, make
79
80
  # sure we have enough width to be at least one character wide. This is
80
81
  # a bit of a hack, but it should work well enough.
81
- unless @min_width
82
+ unless defined?(@min_width) && @min_width
82
83
  min_content_width = [natural_content_width, styled_width_of_single_character].min
83
84
  @min_width = padding_left + padding_right + min_content_width
84
85
  super
@@ -91,15 +92,16 @@ module Prawn
91
92
  @pdf.save_font do
92
93
  options = {}
93
94
  options[:style] = @text_options[:style] if @text_options[:style]
95
+ options[:style] ||= @pdf.font.options[:style] if @pdf.font.options[:style]
94
96
 
95
- @pdf.font(@font || @pdf.font.name, options)
97
+ @pdf.font(defined?(@font) && @font || @pdf.font.family, options)
96
98
 
97
99
  yield
98
100
  end
99
101
  end
100
102
 
101
103
  def with_text_color
102
- if @text_color
104
+ if defined?(@text_color) && @text_color
103
105
  begin
104
106
  old_color = @pdf.fill_color || '000000'
105
107
  @pdf.fill_color(@text_color)
@@ -111,16 +113,18 @@ module Prawn
111
113
  yield
112
114
  end
113
115
  end
114
-
116
+
115
117
  def text_box(extra_options={})
116
- if @text_options[:inline_format]
118
+ if p = @text_options[:inline_format]
119
+ p = [] unless p.is_a?(Array)
117
120
  options = @text_options.dup
118
121
  options.delete(:inline_format)
119
122
  options.merge!(extra_options)
120
123
  options[:document] = @pdf
121
124
 
122
- array = ::Prawn::Text::Formatted::Parser.to_array(@content)
123
- ::Prawn::Text::Formatted::Box.new(array, options)
125
+ array = @pdf.text_formatter.format(@content, *p)
126
+ ::Prawn::Text::Formatted::Box.new(array,
127
+ options.merge(extra_options).merge(:document => @pdf))
124
128
  else
125
129
  ::Prawn::Text::Box.new(@content, @text_options.merge(extra_options).
126
130
  merge(:document => @pdf))
@@ -142,9 +146,7 @@ module Prawn
142
146
  # use whichever character is widest under the current font)
143
147
  #
144
148
  def styled_width_of_single_character
145
- key = (@text_options[:style] == :bold) ? :bold_char_width : :plain_char_width
146
- cache = Thread.current[key] ||= {}
147
- cache[@pdf.font] ||= styled_width_of("M")
149
+ styled_width_of("M")
148
150
  end
149
151
  end
150
152
  end
@@ -8,7 +8,6 @@
8
8
 
9
9
  module Prawn
10
10
  class Table
11
-
12
11
  # Selects the given rows (0-based) for styling. Returns a Cells object --
13
12
  # see the documentation on Cells for things you can do with cells.
14
13
  #
@@ -38,6 +37,8 @@ module Prawn
38
37
  #
39
38
  class Cells < Array
40
39
 
40
+ # @group Experimental API
41
+
41
42
  # Limits selection to the given row or rows. +row_spec+ can be anything
42
43
  # that responds to the === operator selecting a set of 0-based row
43
44
  # numbers; most commonly a number or a range.
@@ -46,7 +47,7 @@ module Prawn
46
47
  # table.rows(3..4) # selects rows four and five
47
48
  #
48
49
  def rows(row_spec)
49
- index_cells unless @indexed
50
+ index_cells unless defined?(@indexed) && @indexed
50
51
  row_spec = transform_spec(row_spec, @first_row, @row_count)
51
52
  Cells.new(@rows[row_spec] ||= select { |c|
52
53
  row_spec.respond_to?(:include?) ?
@@ -57,7 +58,7 @@ module Prawn
57
58
  # Returns the number of rows in the list.
58
59
  #
59
60
  def row_count
60
- index_cells unless @indexed
61
+ index_cells unless defined?(@indexed) && @indexed
61
62
  @row_count
62
63
  end
63
64
 
@@ -69,10 +70,10 @@ module Prawn
69
70
  # table.columns(3..4) # selects columns four and five
70
71
  #
71
72
  def columns(col_spec)
72
- index_cells unless @indexed
73
+ index_cells unless defined?(@indexed) && @indexed
73
74
  col_spec = transform_spec(col_spec, @first_column, @column_count)
74
75
  Cells.new(@columns[col_spec] ||= select { |c|
75
- col_spec.respond_to?(:include?) ?
76
+ col_spec.respond_to?(:include?) ?
76
77
  col_spec.include?(c.column) : col_spec === c.column })
77
78
  end
78
79
  alias_method :column, :columns
@@ -80,7 +81,7 @@ module Prawn
80
81
  # Returns the number of columns in the list.
81
82
  #
82
83
  def column_count
83
- index_cells unless @indexed
84
+ index_cells unless defined?(@indexed) && @indexed
84
85
  @column_count
85
86
  end
86
87
 
@@ -95,12 +96,12 @@ module Prawn
95
96
 
96
97
  # Retrieves a cell based on its 0-based row and column. Returns an
97
98
  # individual Cell, not a Cells collection.
98
- #
99
+ #
99
100
  # table.cells[0, 0].content # => "First cell content"
100
101
  #
101
102
  def [](row, col)
102
103
  return nil if empty?
103
- index_cells unless @indexed
104
+ index_cells unless defined?(@indexed) && @indexed
104
105
  row_array, col_array = @rows[@first_row + row] || [], @columns[@first_column + col] || []
105
106
  if row_array.length < col_array.length
106
107
  row_array.find { |c| c.column == @first_column + col }
@@ -116,7 +117,7 @@ module Prawn
116
117
  cell.row = row
117
118
  cell.column = col
118
119
 
119
- if @indexed
120
+ if defined?(@indexed) && @indexed
120
121
  (@rows[row] ||= []) << cell
121
122
  (@columns[col] ||= []) << cell
122
123
  @first_row = row if !@first_row || row < @first_row
@@ -154,7 +155,6 @@ module Prawn
154
155
  def width
155
156
  widths = {}
156
157
  each do |cell|
157
- index = cell.column
158
158
  per_cell_width = cell.width_ignoring_span.to_f / cell.colspan
159
159
  cell.colspan.times do |n|
160
160
  widths[cell.column+n] = [widths[cell.column+n], per_cell_width].
@@ -173,7 +173,7 @@ module Prawn
173
173
  # Returns maximum width that can contain cells in the set.
174
174
  #
175
175
  def max_width
176
- aggregate_cell_values(:column, :max_width_ignoring_span, :min)
176
+ aggregate_cell_values(:column, :max_width_ignoring_span, :max)
177
177
  end
178
178
 
179
179
  # Returns the total height of all rows in the selected set.
@@ -195,13 +195,13 @@ module Prawn
195
195
  end
196
196
 
197
197
  protected
198
-
198
+
199
199
  # Defers indexing until rows() or columns() is actually called on the
200
200
  # Cells object. Without this, we would needlessly index the leaf nodes of
201
201
  # the object graph, the ones that are only there to be iterated over.
202
202
  #
203
203
  # Make sure to call this before using @rows or @columns.
204
- #
204
+ #
205
205
  def index_cells
206
206
  @rows = {}
207
207
  @columns = {}
@@ -229,9 +229,53 @@ module Prawn
229
229
  #
230
230
  def aggregate_cell_values(row_or_column, meth, aggregate)
231
231
  values = {}
232
+
233
+ #calculate values for all cells that do not span accross multiple cells
234
+ #this ensures that we don't have a problem if the first line includes
235
+ #a cell that spans across multiple cells
236
+ each do |cell|
237
+ #don't take spanned cells
238
+ if cell.colspan == 1 and cell.class != Prawn::Table::Cell::SpanDummy
239
+ index = cell.send(row_or_column)
240
+ values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
241
+ end
242
+ end
243
+
244
+ #if there are only colspanned or rowspanned cells in a table
245
+ spanned_width_needs_fixing = true
246
+
232
247
  each do |cell|
233
248
  index = cell.send(row_or_column)
234
- values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
249
+ if cell.colspan > 1
250
+ #calculate current (old) return value before we do anything
251
+ old_sum = 0
252
+ cell.colspan.times { |i|
253
+ old_sum += values[index+i] unless values[index+i].nil?
254
+ }
255
+
256
+ #calculate future return value
257
+ new_sum = cell.send(meth) * cell.colspan
258
+
259
+ #due to float rounding errors we need to ignore a small difference in the new
260
+ #and the old sum the same had to be done in
261
+ #the column_width_calculator#natural_width
262
+ spanned_width_needs_fixing = ((new_sum - old_sum) > Prawn::FLOAT_PRECISION)
263
+
264
+ if spanned_width_needs_fixing
265
+ #not entirely sure why we need this line, but with it the tests pass
266
+ values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
267
+ #overwrite the old values with the new ones, but only if all entries existed
268
+ entries_exist = true
269
+ cell.colspan.times { |i| entries_exist = false if values[index+i].nil? }
270
+ cell.colspan.times { |i|
271
+ values[index+i] = cell.send(meth) if entries_exist
272
+ }
273
+ end
274
+ else
275
+ if spanned_width_needs_fixing && cell.class == Prawn::Table::Cell::SpanDummy
276
+ values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
277
+ end
278
+ end
235
279
  end
236
280
  values.values.inject(0, &:+)
237
281
  end