prawn 1.0.0.rc1 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/Gemfile +18 -0
  2. data/README.md +5 -3
  3. data/Rakefile +8 -14
  4. data/data/pdfs/nested_pages.pdf +13 -13
  5. data/lib/prawn.rb +3 -1
  6. data/lib/prawn/compatibility.rb +46 -10
  7. data/lib/prawn/core.rb +3 -1
  8. data/lib/prawn/core/document_state.rb +2 -1
  9. data/lib/prawn/core/object_store.rb +61 -5
  10. data/lib/prawn/core/page.rb +3 -6
  11. data/lib/prawn/core/pdf_object.rb +21 -4
  12. data/lib/prawn/core/reference.rb +6 -2
  13. data/lib/prawn/core/text.rb +4 -4
  14. data/lib/prawn/core/text/formatted/line_wrap.rb +23 -8
  15. data/lib/prawn/document.rb +21 -15
  16. data/lib/prawn/document/bounding_box.rb +3 -3
  17. data/lib/prawn/document/column_box.rb +22 -4
  18. data/lib/prawn/document/snapshot.rb +1 -1
  19. data/lib/prawn/encoding.rb +1 -1
  20. data/lib/prawn/errors.rb +4 -0
  21. data/lib/prawn/font.rb +1 -1
  22. data/lib/prawn/font/afm.rb +30 -72
  23. data/lib/prawn/font/ttf.rb +6 -33
  24. data/lib/prawn/graphics.rb +148 -23
  25. data/lib/prawn/graphics/color.rb +8 -1
  26. data/lib/prawn/graphics/patterns.rb +137 -0
  27. data/lib/prawn/images.rb +25 -19
  28. data/lib/prawn/images/jpg.rb +4 -4
  29. data/lib/prawn/images/png.rb +18 -12
  30. data/lib/prawn/security.rb +6 -4
  31. data/lib/prawn/soft_mask.rb +94 -0
  32. data/lib/prawn/table.rb +136 -31
  33. data/lib/prawn/table/cell.rb +260 -29
  34. data/lib/prawn/table/cell/span_dummy.rb +88 -0
  35. data/lib/prawn/table/cell/text.rb +36 -14
  36. data/lib/prawn/table/cells.rb +91 -41
  37. data/lib/prawn/text.rb +3 -2
  38. data/lib/prawn/text/formatted/box.rb +14 -5
  39. data/lib/prawn/text/formatted/fragment.rb +33 -22
  40. data/lib/prawn/text/formatted/parser.rb +5 -2
  41. data/lib/prawn/utilities.rb +44 -0
  42. data/manual/basic_concepts/adding_pages.rb +27 -0
  43. data/manual/basic_concepts/basic_concepts.rb +34 -0
  44. data/manual/basic_concepts/creation.rb +39 -0
  45. data/manual/basic_concepts/cursor.rb +33 -0
  46. data/manual/basic_concepts/measurement.rb +25 -0
  47. data/manual/basic_concepts/origin.rb +38 -0
  48. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  49. data/manual/bounding_box/bounding_box.rb +39 -0
  50. data/manual/bounding_box/bounds.rb +49 -0
  51. data/manual/bounding_box/canvas.rb +24 -0
  52. data/manual/bounding_box/creation.rb +23 -0
  53. data/manual/bounding_box/indentation.rb +46 -0
  54. data/manual/bounding_box/nesting.rb +45 -0
  55. data/manual/bounding_box/russian_boxes.rb +40 -0
  56. data/manual/bounding_box/stretchy.rb +31 -0
  57. data/manual/document_and_page_options/background.rb +27 -0
  58. data/manual/document_and_page_options/document_and_page_options.rb +31 -0
  59. data/manual/document_and_page_options/metadata.rb +23 -0
  60. data/manual/document_and_page_options/page_margins.rb +38 -0
  61. data/manual/document_and_page_options/page_size.rb +34 -0
  62. data/manual/example_file.rb +116 -0
  63. data/manual/example_helper.rb +430 -0
  64. data/manual/example_package.rb +53 -0
  65. data/manual/example_section.rb +46 -0
  66. data/manual/graphics/circle_and_ellipse.rb +22 -0
  67. data/manual/graphics/color.rb +24 -0
  68. data/manual/graphics/common_lines.rb +28 -0
  69. data/manual/graphics/fill_and_stroke.rb +42 -0
  70. data/manual/graphics/fill_rules.rb +37 -0
  71. data/manual/graphics/gradients.rb +37 -0
  72. data/manual/graphics/graphics.rb +58 -0
  73. data/manual/graphics/helper.rb +17 -0
  74. data/manual/graphics/line_width.rb +35 -0
  75. data/manual/graphics/lines_and_curves.rb +41 -0
  76. data/manual/graphics/polygon.rb +29 -0
  77. data/manual/graphics/rectangle.rb +21 -0
  78. data/manual/graphics/rotate.rb +28 -0
  79. data/manual/graphics/scale.rb +41 -0
  80. data/manual/graphics/soft_masks.rb +46 -0
  81. data/manual/graphics/stroke_cap.rb +31 -0
  82. data/manual/graphics/stroke_dash.rb +43 -0
  83. data/manual/graphics/stroke_join.rb +30 -0
  84. data/manual/graphics/translate.rb +29 -0
  85. data/manual/graphics/transparency.rb +35 -0
  86. data/manual/images/absolute_position.rb +23 -0
  87. data/manual/images/fit.rb +21 -0
  88. data/manual/images/horizontal.rb +25 -0
  89. data/manual/images/images.rb +40 -0
  90. data/manual/images/plain_image.rb +18 -0
  91. data/manual/images/scale.rb +22 -0
  92. data/manual/images/vertical.rb +28 -0
  93. data/manual/images/width_and_height.rb +25 -0
  94. data/manual/layout/boxes.rb +27 -0
  95. data/manual/layout/content.rb +25 -0
  96. data/manual/layout/layout.rb +28 -0
  97. data/manual/layout/simple_grid.rb +23 -0
  98. data/manual/manual/cover.rb +26 -0
  99. data/manual/manual/foreword.rb +13 -0
  100. data/manual/manual/how_to_read_this_manual.rb +41 -0
  101. data/manual/manual/manual.rb +36 -0
  102. data/manual/outline/add_subsection_to.rb +61 -0
  103. data/manual/outline/insert_section_after.rb +47 -0
  104. data/manual/outline/outline.rb +32 -0
  105. data/manual/outline/sections_and_pages.rb +67 -0
  106. data/manual/repeatable_content/page_numbering.rb +54 -0
  107. data/manual/repeatable_content/repeatable_content.rb +31 -0
  108. data/manual/repeatable_content/repeater.rb +55 -0
  109. data/manual/repeatable_content/stamp.rb +41 -0
  110. data/manual/security/encryption.rb +31 -0
  111. data/manual/security/permissions.rb +38 -0
  112. data/manual/security/security.rb +28 -0
  113. data/manual/syntax_highlight.rb +52 -0
  114. data/manual/table/basic_block.rb +53 -0
  115. data/manual/table/before_rendering_page.rb +26 -0
  116. data/manual/table/cell_border_lines.rb +24 -0
  117. data/manual/table/cell_borders_and_bg.rb +31 -0
  118. data/manual/table/cell_dimensions.rb +30 -0
  119. data/manual/table/cell_text.rb +38 -0
  120. data/manual/table/column_widths.rb +30 -0
  121. data/manual/table/content_and_subtables.rb +39 -0
  122. data/manual/table/creation.rb +27 -0
  123. data/manual/table/filtering.rb +36 -0
  124. data/manual/table/flow_and_header.rb +17 -0
  125. data/manual/table/image_cells.rb +33 -0
  126. data/manual/table/position.rb +29 -0
  127. data/manual/table/row_colors.rb +20 -0
  128. data/manual/table/span.rb +30 -0
  129. data/manual/table/style.rb +22 -0
  130. data/manual/table/table.rb +52 -0
  131. data/manual/table/width.rb +27 -0
  132. data/manual/templates/full_template.rb +23 -0
  133. data/manual/templates/page_template.rb +47 -0
  134. data/manual/templates/templates.rb +26 -0
  135. data/manual/text/alignment.rb +44 -0
  136. data/manual/text/color.rb +24 -0
  137. data/manual/text/column_box.rb +32 -0
  138. data/manual/text/fallback_fonts.rb +37 -0
  139. data/manual/text/font.rb +41 -0
  140. data/manual/text/font_size.rb +45 -0
  141. data/manual/text/font_style.rb +23 -0
  142. data/manual/text/formatted_callbacks.rb +60 -0
  143. data/manual/text/formatted_text.rb +50 -0
  144. data/manual/text/free_flowing_text.rb +51 -0
  145. data/manual/text/group.rb +29 -0
  146. data/manual/text/inline.rb +43 -0
  147. data/manual/text/kerning_and_character_spacing.rb +39 -0
  148. data/manual/text/leading.rb +25 -0
  149. data/manual/text/line_wrapping.rb +41 -0
  150. data/manual/text/paragraph_indentation.rb +26 -0
  151. data/manual/text/positioned_text.rb +38 -0
  152. data/manual/text/registering_families.rb +48 -0
  153. data/manual/text/rendering_and_color.rb +37 -0
  154. data/manual/text/right_to_left_text.rb +43 -0
  155. data/manual/text/rotation.rb +43 -0
  156. data/manual/text/single_usage.rb +37 -0
  157. data/manual/text/text.rb +75 -0
  158. data/manual/text/text_box_excess.rb +32 -0
  159. data/manual/text/text_box_extensions.rb +45 -0
  160. data/manual/text/text_box_overflow.rb +44 -0
  161. data/manual/text/utf8.rb +28 -0
  162. data/manual/text/win_ansi_charset.rb +59 -0
  163. data/prawn.gemspec +10 -7
  164. data/spec/bounding_box_spec.rb +107 -17
  165. data/spec/cell_spec.rb +66 -40
  166. data/spec/column_box_spec.rb +33 -0
  167. data/spec/document_spec.rb +45 -24
  168. data/spec/extensions/encoding_helpers.rb +6 -0
  169. data/spec/extensions/mocha.rb +1 -0
  170. data/spec/font_spec.rb +71 -53
  171. data/spec/formatted_text_arranger_spec.rb +19 -19
  172. data/spec/formatted_text_box_spec.rb +16 -16
  173. data/spec/formatted_text_fragment_spec.rb +6 -6
  174. data/spec/graphics_spec.rb +96 -31
  175. data/spec/grid_spec.rb +2 -2
  176. data/spec/images_spec.rb +18 -10
  177. data/spec/jpg_spec.rb +1 -1
  178. data/spec/line_wrap_spec.rb +14 -14
  179. data/spec/measurement_units_spec.rb +2 -2
  180. data/spec/name_tree_spec.rb +6 -6
  181. data/spec/object_store_spec.rb +17 -17
  182. data/spec/outline_spec.rb +35 -17
  183. data/spec/pdf_object_spec.rb +3 -1
  184. data/spec/png_spec.rb +22 -19
  185. data/spec/reference_spec.rb +24 -1
  186. data/spec/repeater_spec.rb +9 -9
  187. data/spec/security_spec.rb +3 -3
  188. data/spec/snapshot_spec.rb +3 -3
  189. data/spec/soft_mask_spec.rb +117 -0
  190. data/spec/span_spec.rb +4 -4
  191. data/spec/spec_helper.rb +12 -6
  192. data/spec/stamp_spec.rb +12 -12
  193. data/spec/stroke_styles_spec.rb +5 -5
  194. data/spec/table_spec.rb +458 -88
  195. data/spec/template_spec.rb +108 -54
  196. data/spec/text_at_spec.rb +17 -17
  197. data/spec/text_box_spec.rb +76 -45
  198. data/spec/text_rendering_mode_spec.rb +5 -5
  199. data/spec/text_spacing_spec.rb +4 -4
  200. data/spec/text_spec.rb +44 -40
  201. metadata +419 -250
  202. data/lib/prawn/graphics/gradient.rb +0 -84
  203. data/lib/prawn/security/arcfour.rb +0 -51
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # cell.rb: Table cell drawing.
4
4
  #
@@ -6,10 +6,11 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
+ require 'date'
9
10
  module Prawn
10
11
  class Document
11
12
 
12
- # Instantiates and draws a cell on the document.
13
+ # Instantiates and draws a cell on the document.
13
14
  #
14
15
  # cell(:content => "Hello world!", :at => [12, 34])
15
16
  #
@@ -20,9 +21,9 @@ module Prawn
20
21
  cell.draw
21
22
  cell
22
23
  end
23
-
24
- # Set up, but do not draw, a cell. Useful for creating cells with
25
- # formatting options to be inserted into a Table. Call +draw+ on the
24
+
25
+ # Set up, but do not draw, a cell. Useful for creating cells with
26
+ # formatting options to be inserted into a Table. Call +draw+ on the
26
27
  # resulting Cell to ink it.
27
28
  #
28
29
  # See the documentation on Prawn::Cell for details on the arguments.
@@ -34,7 +35,7 @@ module Prawn
34
35
  end
35
36
 
36
37
  class Table
37
-
38
+
38
39
  # A Cell is a rectangular area of the page into which content is drawn. It
39
40
  # has a framework for sizing itself and adding padding and simple styling.
40
41
  # There are several standard Cell subclasses that handle things like text,
@@ -53,20 +54,58 @@ module Prawn
53
54
  #
54
55
  attr_reader :padding
55
56
 
56
- # If provided, the minimum width that this cell will permit.
57
- #
58
- def min_width
57
+ # If provided, the minimum width that this cell in its column will permit.
58
+ #
59
+ def min_width_ignoring_span
59
60
  set_width_constraints
60
61
  @min_width
61
62
  end
62
-
63
- # If provided, the maximum width that this cell can be drawn in.
63
+
64
+ # Minimum width of the entire span group this cell controls.
64
65
  #
65
- def max_width
66
+ def min_width
67
+ return min_width_ignoring_span if @colspan == 1
68
+
69
+ # Sum up the largest min-width from each column, including myself.
70
+ min_widths = Hash.new(0)
71
+ dummy_cells.each do |cell|
72
+ min_widths[cell.column] =
73
+ [min_widths[cell.column], cell.min_width].max
74
+ end
75
+ min_widths[column] = [min_widths[column], min_width_ignoring_span].max
76
+ min_widths.values.inject(0, &:+)
77
+ end
78
+
79
+ # Min-width of the span divided by the number of columns.
80
+ #
81
+ def avg_spanned_min_width
82
+ min_width.to_f / colspan
83
+ end
84
+
85
+ # If provided, the maximum width that this cell can be drawn in, within
86
+ # its column.
87
+ #
88
+ def max_width_ignoring_span
66
89
  set_width_constraints
67
90
  @max_width
68
91
  end
69
92
 
93
+ # Maximum width of the entire span group this cell controls.
94
+ #
95
+ def max_width
96
+ return max_width_ignoring_span if @colspan == 1
97
+
98
+ # Sum the smallest max-width from each column in the group, including
99
+ # myself.
100
+ max_widths = Hash.new(0)
101
+ dummy_cells.each do |cell|
102
+ max_widths[cell.column] =
103
+ [max_widths[cell.column], cell.max_width].min
104
+ end
105
+ max_widths[column] = [max_widths[column], max_width_ignoring_span].min
106
+ max_widths.values.inject(0, &:+)
107
+ end
108
+
70
109
  # Manually specify the cell's height.
71
110
  #
72
111
  attr_writer :height
@@ -83,12 +122,16 @@ module Prawn
83
122
  # HTML RGB-format ("ccffff") border colors: [top, right, bottom, left].
84
123
  #
85
124
  attr_reader :border_colors
125
+
126
+ # Line style
127
+ #
128
+ attr_reader :border_lines
86
129
 
87
130
  # Specifies the content for the cell. Must be a "cellable" object. See the
88
131
  # "Data" section of the Prawn::Table documentation for details on cellable
89
132
  # objects.
90
133
  #
91
- attr_accessor :content
134
+ attr_accessor :content
92
135
 
93
136
  # The background color, if any, for this cell. Specified in HTML RGB
94
137
  # format, e.g., "ccffff". The background is drawn under the whole cell,
@@ -96,6 +139,20 @@ module Prawn
96
139
  #
97
140
  attr_accessor :background_color
98
141
 
142
+ # Number of columns this cell spans. Defaults to 1.
143
+ #
144
+ attr_reader :colspan
145
+
146
+ # Number of rows this cell spans. Defaults to 1.
147
+ #
148
+ attr_reader :rowspan
149
+
150
+ # Array of SpanDummy cells (if any) that represent the other cells in
151
+ # this span group. They know their own width / height, but do not draw
152
+ # anything.
153
+ #
154
+ attr_reader :dummy_cells # :nodoc:
155
+
99
156
  # Instantiates a Cell based on the given options. The particular class of
100
157
  # cell returned depends on the :content argument. See the Prawn::Table
101
158
  # documentation under "Data" for allowable content types.
@@ -104,7 +161,7 @@ module Prawn
104
161
  at = options.delete(:at) || [0, pdf.cursor]
105
162
  content = content.to_s if content.nil? || content.kind_of?(Numeric) ||
106
163
  content.kind_of?(Date)
107
-
164
+
108
165
  if content.is_a?(Hash)
109
166
  if img = content[:image]
110
167
  return Cell::Image.new(pdf, at, content)
@@ -115,6 +172,8 @@ module Prawn
115
172
  options[:content] = content
116
173
  end
117
174
 
175
+ options[:content] = content = "" if content.nil?
176
+
118
177
  case content
119
178
  when Prawn::Table::Cell
120
179
  content
@@ -153,8 +212,14 @@ module Prawn
153
212
  @borders = [:top, :bottom, :left, :right]
154
213
  @border_widths = [1] * 4
155
214
  @border_colors = ['000000'] * 4
215
+ @border_lines = [:solid] * 4
216
+ @colspan = 1
217
+ @rowspan = 1
218
+ @dummy_cells = []
156
219
 
157
220
  options.each { |k, v| send("#{k}=", v) }
221
+
222
+ @initializer_run = true
158
223
  end
159
224
 
160
225
  # Supports setting multiple properties at once.
@@ -174,14 +239,33 @@ module Prawn
174
239
  block.call(self) if block
175
240
  end
176
241
 
177
- # Returns the cell's width in points, inclusive of padding.
242
+ # Returns the width of the cell in its first column alone, ignoring any
243
+ # colspans.
178
244
  #
179
- def width
245
+ def width_ignoring_span
180
246
  # We can't ||= here because the FP error accumulates on the round-trip
181
247
  # from #content_width.
182
248
  @width || (content_width + padding_left + padding_right)
183
249
  end
184
250
 
251
+ # Returns the cell's width in points, inclusive of padding. If the cell is
252
+ # the master cell of a colspan, returns the width of the entire span
253
+ # group.
254
+ #
255
+ def width
256
+ return width_ignoring_span if @colspan == 1 && @rowspan == 1
257
+
258
+ # We're in a span group; get the maximum width per column (including
259
+ # the master cell) and sum each column.
260
+ column_widths = Hash.new(0)
261
+ dummy_cells.each do |cell|
262
+ column_widths[cell.column] =
263
+ [column_widths[cell.column], cell.width].max
264
+ end
265
+ column_widths[column] = [column_widths[column], width_ignoring_span].max
266
+ column_widths.values.inject(0, &:+)
267
+ end
268
+
185
269
  # Manually sets the cell's width, inclusive of padding.
186
270
  #
187
271
  def width=(w)
@@ -198,40 +282,113 @@ module Prawn
198
282
  natural_content_width
199
283
  end
200
284
 
285
+ # Width of the entire span group.
286
+ #
287
+ def spanned_content_width
288
+ width - padding_left - padding_right
289
+ end
290
+
201
291
  # Returns the width this cell would naturally take on, absent other
202
292
  # constraints. Must be implemented in subclasses.
203
293
  #
204
294
  def natural_content_width
205
- raise NotImplementedError,
295
+ raise NotImplementedError,
206
296
  "subclasses must implement natural_content_width"
207
297
  end
208
298
 
209
- # Returns the cell's height in points, inclusive of padding.
299
+ # Returns the cell's height in points, inclusive of padding, in its first
300
+ # row only.
210
301
  #
211
- def height
302
+ def height_ignoring_span
212
303
  # We can't ||= here because the FP error accumulates on the round-trip
213
304
  # from #content_height.
214
305
  @height || (content_height + padding_top + padding_bottom)
215
306
  end
216
307
 
308
+ # Returns the cell's height in points, inclusive of padding. If the cell
309
+ # is the master cell of a rowspan, returns the width of the entire span
310
+ # group.
311
+ #
312
+ def height
313
+ return height_ignoring_span if @colspan == 1 && @rowspan == 1
314
+
315
+ # We're in a span group; get the maximum height per row (including the
316
+ # master cell) and sum each row.
317
+ row_heights = Hash.new(0)
318
+ dummy_cells.each do |cell|
319
+ row_heights[cell.row] = [row_heights[cell.row], cell.height].max
320
+ end
321
+ row_heights[row] = [row_heights[row], height_ignoring_span].max
322
+ row_heights.values.inject(0, &:+)
323
+ end
324
+
217
325
  # Returns the height of the bare content in the cell, excluding padding.
218
326
  #
219
327
  def content_height
220
328
  if @height # manually set
221
329
  return @height - padding_top - padding_bottom
222
330
  end
223
-
331
+
224
332
  natural_content_height
225
333
  end
226
334
 
335
+ # Height of the entire span group.
336
+ #
337
+ def spanned_content_height
338
+ height - padding_top - padding_bottom
339
+ end
340
+
227
341
  # Returns the height this cell would naturally take on, absent
228
342
  # constraints. Must be implemented in subclasses.
229
343
  #
230
344
  def natural_content_height
231
- raise NotImplementedError,
345
+ raise NotImplementedError,
232
346
  "subclasses must implement natural_content_height"
233
347
  end
234
348
 
349
+ # Indicates the number of columns that this cell is to span. Defaults to
350
+ # 1.
351
+ #
352
+ # This must be provided as part of the table data, like so:
353
+ #
354
+ # pdf.table([["foo", {:content => "bar", :colspan => 2}]])
355
+ #
356
+ # Setting colspan from the initializer block is invalid because layout
357
+ # has already run. For example, this will NOT work:
358
+ #
359
+ # pdf.table([["foo", "bar"]]) { cells[0, 1].colspan = 2 }
360
+ #
361
+ def colspan=(span)
362
+ if @initializer_run
363
+ raise Prawn::Errors::InvalidTableSpan,
364
+ "colspan must be provided in the table's structure, never in the " +
365
+ "initialization block. See Prawn's documentation for details."
366
+ end
367
+
368
+ @colspan = span
369
+ end
370
+
371
+ # Indicates the number of rows that this cell is to span. Defaults to 1.
372
+ #
373
+ # This must be provided as part of the table data, like so:
374
+ #
375
+ # pdf.table([["foo", {:content => "bar", :rowspan => 2}], ["baz"]])
376
+ #
377
+ # Setting rowspan from the initializer block is invalid because layout
378
+ # has already run. For example, this will NOT work:
379
+ #
380
+ # pdf.table([["foo", "bar"], ["baz"]]) { cells[0, 1].rowspan = 2 }
381
+ #
382
+ def rowspan=(span)
383
+ if @initializer_run
384
+ raise Prawn::Errors::InvalidTableSpan,
385
+ "rowspan must be provided in the table's structure, never in the " +
386
+ "initialization block. See Prawn's documentation for details."
387
+ end
388
+
389
+ @rowspan = span
390
+ end
391
+
235
392
  # Draws the cell onto the document. Pass in a point [x,y] to override the
236
393
  # location at which the cell is drawn.
237
394
  #
@@ -240,7 +397,7 @@ module Prawn
240
397
  # content are all drawn in correct order so as not to overlap.
241
398
  #
242
399
  def draw(pt=[x, y])
243
- self.class.draw_cells([[self, pt]])
400
+ Prawn::Table::Cell.draw_cells([[self, pt]])
244
401
  end
245
402
 
246
403
  # Given an array of pairs [cell, pt], draws each cell at its
@@ -263,9 +420,9 @@ module Prawn
263
420
  #
264
421
  def draw_bounded_content(pt)
265
422
  @pdf.float do
266
- @pdf.bounding_box([pt[0] + padding_left, pt[1] - padding_top],
267
- :width => content_width + FPTolerance,
268
- :height => content_height + FPTolerance) do
423
+ @pdf.bounding_box([pt[0] + padding_left, pt[1] - padding_top],
424
+ :width => spanned_content_width + FPTolerance,
425
+ :height => spanned_content_height + FPTolerance) do
269
426
  draw_content
270
427
  end
271
428
  end
@@ -323,7 +480,7 @@ module Prawn
323
480
  def padding_top
324
481
  @padding[0]
325
482
  end
326
-
483
+
327
484
  def padding_top=(val)
328
485
  @padding[0] = val
329
486
  end
@@ -331,7 +488,7 @@ module Prawn
331
488
  def padding_right
332
489
  @padding[1]
333
490
  end
334
-
491
+
335
492
  def padding_right=(val)
336
493
  @padding[1] = val
337
494
  end
@@ -339,7 +496,7 @@ module Prawn
339
496
  def padding_bottom
340
497
  @padding[2]
341
498
  end
342
-
499
+
343
500
  def padding_bottom=(val)
344
501
  @padding[2] = val
345
502
  end
@@ -347,7 +504,7 @@ module Prawn
347
504
  def padding_left
348
505
  @padding[3]
349
506
  end
350
-
507
+
351
508
  def padding_left=(val)
352
509
  @padding[3] = val
353
510
  end
@@ -483,6 +640,66 @@ module Prawn
483
640
  @min_width ||= padding_left + padding_right
484
641
  @max_width ||= @pdf.bounds.width
485
642
  end
643
+
644
+ # Sets border line style on this cell. The argument can be one of:
645
+ #
646
+ # Possible values are: :solid, :dashed, :dotted
647
+ #
648
+ # * one value (sets all lines)
649
+ # * a two-element array [vertical, horizontal]
650
+ # * a three-element array [top, horizontal, bottom]
651
+ # * a four-element array [top, right, bottom, left]
652
+ #
653
+ def border_line=(line)
654
+ @border_lines = case
655
+ when line.nil?
656
+ [:solid] * 4
657
+ when line.length == 1 # all lines
658
+ [line[0]] * 4
659
+ when line.length == 2
660
+ [line[0], line[1], line[0], line[1]]
661
+ when line.length == 3
662
+ [line[0], line[1], line[2], line[1]]
663
+ when line.length == 4
664
+ [line[0], line[1], line[2], line[3]]
665
+ else
666
+ raise ArgumentError, "border_line must be one of :solid, :dashed, "
667
+ ":dotted or an array [v,h] or [t,r,b,l]"
668
+ end
669
+ end
670
+ alias_method :border_lines=, :border_line=
671
+
672
+ def border_top_line
673
+ @borders.include?(:top) ? @border_lines[0] : 0
674
+ end
675
+
676
+ def border_top_line=(val)
677
+ @border_lines[0] = val
678
+ end
679
+
680
+ def border_right_line
681
+ @borders.include?(:right) ? @border_lines[1] : 0
682
+ end
683
+
684
+ def border_right_line=(val)
685
+ @border_lines[1] = val
686
+ end
687
+
688
+ def border_bottom_line
689
+ @borders.include?(:bottom) ? @border_lines[2] : 0
690
+ end
691
+
692
+ def border_bottom_line=(val)
693
+ @border_lines[2] = val
694
+ end
695
+
696
+ def border_left_line
697
+ @borders.include?(:left) ? @border_lines[3] : 0
698
+ end
699
+
700
+ def border_left_line=(val)
701
+ @border_lines[3] = val
702
+ end
486
703
 
487
704
  # Draws the cell's background color.
488
705
  #
@@ -508,6 +725,7 @@ module Prawn
508
725
  idx = {:top => 0, :right => 1, :bottom => 2, :left => 3}[border]
509
726
  border_color = @border_colors[idx]
510
727
  border_width = @border_widths[idx]
728
+ border_line = @border_lines[idx]
511
729
 
512
730
  next if border_width <= 0
513
731
 
@@ -526,9 +744,22 @@ module Prawn
526
744
  [x+width, y - height - (border_bottom_width / 2.0)]]
527
745
  end
528
746
 
747
+ case border_line
748
+ when :dashed
749
+ @pdf.dash border_width * 4
750
+ when :dotted
751
+ @pdf.dash border_width, :space => border_width * 2
752
+ when :solid
753
+ # normal line style
754
+ else
755
+ raise ArgumentError, "border_line must be :solid, :dotted or" +
756
+ " :dashed"
757
+ end
758
+
529
759
  @pdf.line_width = border_width
530
760
  @pdf.stroke_color = border_color
531
761
  @pdf.stroke_line(from, to)
762
+ @pdf.undash
532
763
  end
533
764
  end
534
765
  end