prawn 0.11.1 → 0.12.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.
- data/GPLv2 +340 -0
- data/GPLv3 +674 -0
- data/README.md +96 -0
- data/Rakefile +0 -12
- data/examples/example_helper.rb +3 -0
- data/lib/prawn.rb +1 -1
- data/lib/prawn/core/page.rb +4 -2
- data/lib/prawn/core/pdf_object.rb +7 -7
- data/lib/prawn/core/text/formatted/arranger.rb +2 -1
- data/lib/prawn/core/text/formatted/line_wrap.rb +2 -1
- data/lib/prawn/core/text/formatted/wrap.rb +5 -1
- data/lib/prawn/document.rb +135 -112
- data/lib/prawn/document/bounding_box.rb +51 -5
- data/lib/prawn/document/column_box.rb +0 -19
- data/lib/prawn/document/internals.rb +1 -0
- data/lib/prawn/document/snapshot.rb +3 -0
- data/lib/prawn/font.rb +4 -3
- data/lib/prawn/font/afm.rb +11 -2
- data/lib/prawn/font/ttf.rb +15 -0
- data/lib/prawn/images.rb +1 -1
- data/lib/prawn/table.rb +23 -7
- data/lib/prawn/table/cell.rb +31 -9
- data/lib/prawn/table/cell/text.rb +2 -2
- data/prawn.gemspec +5 -6
- data/spec/bounding_box_spec.rb +157 -0
- data/spec/data/curves.pdf +66 -0
- data/spec/document_spec.rb +59 -4
- data/spec/extensions/mocha.rb +1 -3
- data/spec/font_spec.rb +23 -0
- data/spec/formatted_text_box_spec.rb +40 -0
- data/spec/images_spec.rb +7 -0
- data/spec/object_store_spec.rb +3 -3
- data/spec/snapshot_spec.rb +33 -0
- data/spec/table_spec.rb +75 -0
- data/spec/template_spec.rb +11 -5
- data/spec/text_spacing_spec.rb +18 -0
- data/spec/text_spec.rb +32 -0
- metadata +217 -283
- data/HACKING +0 -50
- data/README +0 -141
- data/examples/bounding_box/bounding_boxes.rb +0 -44
- data/examples/bounding_box/indentation.rb +0 -35
- data/examples/bounding_box/stretched_nesting.rb +0 -68
- data/examples/general/background.rb +0 -24
- data/examples/general/canvas.rb +0 -16
- data/examples/general/float.rb +0 -12
- data/examples/general/margin.rb +0 -37
- data/examples/general/measurement_units.rb +0 -52
- data/examples/general/metadata-info.rb +0 -17
- data/examples/general/multi_page_layout.rb +0 -19
- data/examples/general/outlines.rb +0 -67
- data/examples/general/page_geometry.rb +0 -32
- data/examples/general/page_numbering.rb +0 -40
- data/examples/general/page_templates.rb +0 -20
- data/examples/general/repeaters.rb +0 -48
- data/examples/general/stamp.rb +0 -42
- data/examples/general/templates.rb +0 -14
- data/examples/graphics/basic_images.rb +0 -24
- data/examples/graphics/curves.rb +0 -12
- data/examples/graphics/hexagon.rb +0 -14
- data/examples/graphics/image_fit.rb +0 -16
- data/examples/graphics/image_flow.rb +0 -38
- data/examples/graphics/image_position.rb +0 -18
- data/examples/graphics/line.rb +0 -33
- data/examples/graphics/polygons.rb +0 -17
- data/examples/graphics/rounded_polygons.rb +0 -20
- data/examples/graphics/rounded_rectangle.rb +0 -21
- data/examples/graphics/ruport_style_helpers.rb +0 -20
- data/examples/graphics/stroke_bounds.rb +0 -21
- data/examples/graphics/stroke_cap_and_join.rb +0 -46
- data/examples/graphics/stroke_dash.rb +0 -43
- data/examples/graphics/transformations.rb +0 -53
- data/examples/graphics/transparency.rb +0 -27
- data/examples/grid/bounding_boxes.rb +0 -22
- data/examples/grid/column_gutter_grid.rb +0 -21
- data/examples/grid/multi_boxes.rb +0 -52
- data/examples/grid/show_grid.rb +0 -14
- data/examples/grid/simple_grid.rb +0 -21
- data/examples/m17n/chinese_text_wrapping.rb +0 -18
- data/examples/m17n/euro.rb +0 -16
- data/examples/m17n/utf8.rb +0 -14
- data/examples/security/hello_foo.rb +0 -9
- data/examples/table/borders.rb +0 -25
- data/examples/table/cell.rb +0 -13
- data/examples/table/checkerboard.rb +0 -23
- data/examples/table/inline_format_table.rb +0 -13
- data/examples/table/multi_page_table.rb +0 -10
- data/examples/table/simple_table.rb +0 -25
- data/examples/table/subtable.rb +0 -13
- data/examples/table/widths.rb +0 -21
- data/examples/text/alignment.rb +0 -19
- data/examples/text/character_spacing.rb +0 -13
- data/examples/text/dfont.rb +0 -49
- data/examples/text/family_based_styling.rb +0 -25
- data/examples/text/font_size.rb +0 -34
- data/examples/text/inline_format.rb +0 -104
- data/examples/text/kerning.rb +0 -31
- data/examples/text/rendering_mode.rb +0 -21
- data/examples/text/rotated.rb +0 -99
- data/examples/text/shaped_text_box.rb +0 -32
- data/examples/text/simple_text.rb +0 -18
- data/examples/text/simple_text_ttf.rb +0 -18
- data/examples/text/span.rb +0 -30
- data/examples/text/text_box.rb +0 -90
- data/examples/text/text_box_returning_excess.rb +0 -52
- data/examples/text/text_flow.rb +0 -68
@@ -181,13 +181,20 @@ module Prawn
|
|
181
181
|
private
|
182
182
|
|
183
183
|
def init_bounding_box(user_block, options={}, &init_block)
|
184
|
+
unless user_block
|
185
|
+
raise ArgumentError,
|
186
|
+
"bounding boxes require a block to be drawn within the box"
|
187
|
+
end
|
188
|
+
|
184
189
|
parent_box = @bounding_box
|
185
190
|
|
186
191
|
init_block.call(parent_box)
|
187
192
|
|
188
193
|
self.y = @bounding_box.absolute_top
|
189
194
|
user_block.call
|
190
|
-
|
195
|
+
unless options[:hold_position] || @bounding_box.stretchy?
|
196
|
+
self.y = @bounding_box.absolute_bottom
|
197
|
+
end
|
191
198
|
|
192
199
|
created_box, @bounding_box = @bounding_box, parent_box
|
193
200
|
|
@@ -435,17 +442,23 @@ module Prawn
|
|
435
442
|
|
436
443
|
# an alias for absolute_left
|
437
444
|
def left_side
|
438
|
-
|
445
|
+
absolute_left
|
439
446
|
end
|
440
447
|
|
441
448
|
# an alias for absolute_right
|
442
449
|
def right_side
|
443
|
-
|
450
|
+
absolute_right
|
444
451
|
end
|
445
452
|
|
446
|
-
#
|
453
|
+
# Moves to the top of the next page of the document, starting a new page
|
454
|
+
# if necessary.
|
455
|
+
#
|
447
456
|
def move_past_bottom
|
448
|
-
@document.
|
457
|
+
if @document.page_number == @document.page_count
|
458
|
+
@document.start_new_page
|
459
|
+
else
|
460
|
+
@document.go_to_page(@document.page_number + 1)
|
461
|
+
end
|
449
462
|
end
|
450
463
|
|
451
464
|
|
@@ -458,6 +471,39 @@ module Prawn
|
|
458
471
|
!@height
|
459
472
|
end
|
460
473
|
|
474
|
+
# Returns the innermost non-stretchy bounding box.
|
475
|
+
#
|
476
|
+
def reference_bounds
|
477
|
+
if stretchy?
|
478
|
+
raise "Can't find reference bounds: my parent is unset" unless @parent
|
479
|
+
@parent.reference_bounds
|
480
|
+
else
|
481
|
+
self
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# Returns a deep copy of these bounds (including all parent bounds but
|
486
|
+
# not copying the reference to the Document).
|
487
|
+
#
|
488
|
+
def deep_copy
|
489
|
+
copy = dup
|
490
|
+
# Deep-copy the parent bounds
|
491
|
+
copy.instance_variable_set("@parent", if BoundingBox === @parent
|
492
|
+
@parent.deep_copy
|
493
|
+
end)
|
494
|
+
copy.instance_variable_set("@document", nil)
|
495
|
+
copy
|
496
|
+
end
|
497
|
+
|
498
|
+
# Restores a copy of the bounds taken by BoundingBox.deep_copy in the
|
499
|
+
# context of the given +document+. Does *not* set the bounds of the
|
500
|
+
# document to the resulting BoundingBox, only returns it.
|
501
|
+
#
|
502
|
+
def self.restore_deep_copy(bounds, document)
|
503
|
+
bounds.instance_variable_set("@document", document)
|
504
|
+
bounds
|
505
|
+
end
|
506
|
+
|
461
507
|
end
|
462
508
|
|
463
509
|
end
|
@@ -41,25 +41,6 @@ module Prawn
|
|
41
41
|
@bounding_box = parent_box
|
42
42
|
end
|
43
43
|
|
44
|
-
# Template methods to support ColumnBox extensions
|
45
|
-
class BoundingBox
|
46
|
-
|
47
|
-
# an alias for absolute_left
|
48
|
-
def left_side
|
49
|
-
absolute_left
|
50
|
-
end
|
51
|
-
|
52
|
-
# an alias for absolute_right
|
53
|
-
def right_side
|
54
|
-
absolute_right
|
55
|
-
end
|
56
|
-
|
57
|
-
# starts a new page
|
58
|
-
def move_past_bottom
|
59
|
-
@document.start_new_page
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
44
|
# Implements the necessary functionality to allow Document#column_box to
|
64
45
|
# work.
|
65
46
|
#
|
@@ -51,6 +51,7 @@ module Prawn
|
|
51
51
|
# between the old and new copies.
|
52
52
|
{:page_content => state.page.content.deep_copy,
|
53
53
|
:current_page => state.page.dictionary.deep_copy(share=[:Parent]),
|
54
|
+
:bounds => bounds.deep_copy,
|
54
55
|
:page_number => page_number,
|
55
56
|
:page_kids => state.store.pages.data[:Kids].map{|kid| kid.identifier},
|
56
57
|
:dests => names? &&
|
@@ -77,6 +78,8 @@ module Prawn
|
|
77
78
|
state.store.pages.data[:Kids] = shot[:page_kids].map{|id| state.store[id]}
|
78
79
|
state.store.pages.data[:Count] = shot[:page_kids].size
|
79
80
|
|
81
|
+
self.bounds = BoundingBox.restore_deep_copy(shot[:bounds], self)
|
82
|
+
|
80
83
|
if shot[:dests]
|
81
84
|
names.data[:Dests] = shot[:dests]
|
82
85
|
end
|
data/lib/prawn/font.rb
CHANGED
@@ -52,7 +52,7 @@ module Prawn
|
|
52
52
|
raise Prawn::Errors::NotOnPage
|
53
53
|
end
|
54
54
|
|
55
|
-
new_font = find_font(name, options)
|
55
|
+
new_font = find_font(name.to_s, options)
|
56
56
|
|
57
57
|
if block_given?
|
58
58
|
save_font do
|
@@ -179,7 +179,7 @@ module Prawn
|
|
179
179
|
# custom ones, like :thin, and use them in font calls.
|
180
180
|
#
|
181
181
|
def font_families
|
182
|
-
@font_families ||= Hash.new
|
182
|
+
@font_families ||= Hash.new.merge!(
|
183
183
|
{ "Courier" => { :bold => "Courier-Bold",
|
184
184
|
:italic => "Courier-Oblique",
|
185
185
|
:bold_italic => "Courier-BoldOblique",
|
@@ -217,7 +217,8 @@ module Prawn
|
|
217
217
|
# it and redefine the width calculation behavior.
|
218
218
|
#++
|
219
219
|
def width_of(string, options={})
|
220
|
-
font.compute_width_of(string, options) +
|
220
|
+
font.compute_width_of(string, options) +
|
221
|
+
(character_spacing * font.character_count(string))
|
221
222
|
end
|
222
223
|
end
|
223
224
|
|
data/lib/prawn/font/afm.rb
CHANGED
@@ -94,6 +94,12 @@ module Prawn
|
|
94
94
|
"Arguments to text methods must be UTF-8 encoded"
|
95
95
|
end
|
96
96
|
|
97
|
+
# Returns the number of characters in +str+ (a WinAnsi-encoded string).
|
98
|
+
#
|
99
|
+
def character_count(str)
|
100
|
+
str.length
|
101
|
+
end
|
102
|
+
|
97
103
|
# Perform any changes to the string that need to happen
|
98
104
|
# before it is rendered to the canvas. Returns an array of
|
99
105
|
# subset "chunks", where each chunk is an array of two elements.
|
@@ -210,8 +216,11 @@ module Prawn
|
|
210
216
|
end
|
211
217
|
|
212
218
|
def latin_kern_pairs_table
|
213
|
-
@kern_pairs_table
|
214
|
-
|
219
|
+
return @kern_pairs_table if defined?(@kern_pairs_table)
|
220
|
+
|
221
|
+
character_hash = Hash[Encoding::WinAnsi::CHARACTERS.zip((0..Encoding::WinAnsi::CHARACTERS.size).to_a)]
|
222
|
+
@kern_pairs_table = @kern_pairs.inject({}) do |h,p|
|
223
|
+
h[p[0].map { |n| character_hash[n] }] = p[1]
|
215
224
|
h
|
216
225
|
end
|
217
226
|
end
|
data/lib/prawn/font/ttf.rb
CHANGED
@@ -190,6 +190,16 @@ module Prawn
|
|
190
190
|
cmap[code] > 0
|
191
191
|
end
|
192
192
|
|
193
|
+
# Returns the number of characters in +str+ (a UTF-8-encoded string).
|
194
|
+
#
|
195
|
+
def character_count(str)
|
196
|
+
if str.respond_to?(:encode)
|
197
|
+
str.length
|
198
|
+
else
|
199
|
+
str.unpack("U*").length
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
193
203
|
private
|
194
204
|
|
195
205
|
def cmap
|
@@ -233,6 +243,11 @@ module Prawn
|
|
233
243
|
|
234
244
|
def character_width_by_code(code)
|
235
245
|
return 0 unless cmap[code]
|
246
|
+
|
247
|
+
# Some TTF fonts have nonzero widths for \n (UTF-8 / ASCII code: 10).
|
248
|
+
# Patch around this as we'll never be drawing a newline with a width.
|
249
|
+
return 0.0 if code == 10
|
250
|
+
|
236
251
|
@char_widths[code] ||= Integer(hmtx.widths[cmap[code]] * scale_factor)
|
237
252
|
end
|
238
253
|
|
data/lib/prawn/images.rb
CHANGED
data/lib/prawn/table.rb
CHANGED
@@ -121,6 +121,7 @@ module Prawn
|
|
121
121
|
@pdf = document
|
122
122
|
@cells = make_cells(data)
|
123
123
|
@header = false
|
124
|
+
@epsilon = 1e-9
|
124
125
|
options.each { |k, v| send("#{k}=", v) }
|
125
126
|
|
126
127
|
if block
|
@@ -168,7 +169,7 @@ module Prawn
|
|
168
169
|
when Hash
|
169
170
|
widths.each { |i, w| column(i).width = w }
|
170
171
|
when Numeric
|
171
|
-
|
172
|
+
cells.width = widths
|
172
173
|
else
|
173
174
|
raise ArgumentError, "cannot interpret column widths"
|
174
175
|
end
|
@@ -227,7 +228,7 @@ module Prawn
|
|
227
228
|
|
228
229
|
# Reference bounds are the non-stretchy bounds used to decide when to
|
229
230
|
# flow to a new column / page.
|
230
|
-
ref_bounds = @pdf.
|
231
|
+
ref_bounds = @pdf.reference_bounds
|
231
232
|
|
232
233
|
last_y = @pdf.y
|
233
234
|
|
@@ -258,9 +259,17 @@ module Prawn
|
|
258
259
|
end
|
259
260
|
end
|
260
261
|
|
262
|
+
# Track cells to be drawn on this page. They will all be drawn when this
|
263
|
+
# page is finished.
|
264
|
+
cells_this_page = []
|
265
|
+
|
261
266
|
@cells.each do |cell|
|
262
267
|
if cell.height > (cell.y + offset) - ref_bounds.absolute_bottom &&
|
263
268
|
cell.row > started_new_page_at_row
|
269
|
+
# Ink all cells on the current page
|
270
|
+
Cell.draw_cells(cells_this_page)
|
271
|
+
cells_this_page = []
|
272
|
+
|
264
273
|
# start a new page or column
|
265
274
|
@pdf.bounds.move_past_bottom
|
266
275
|
draw_header unless cell.row == 0
|
@@ -285,9 +294,11 @@ module Prawn
|
|
285
294
|
cell.background_color = @row_colors[index % @row_colors.length]
|
286
295
|
end
|
287
296
|
|
288
|
-
cell
|
297
|
+
cells_this_page << [cell, [x, y]]
|
289
298
|
last_y = y
|
290
299
|
end
|
300
|
+
# Draw the last page of cells
|
301
|
+
Cell.draw_cells(cells_this_page)
|
291
302
|
|
292
303
|
@pdf.move_cursor_to(last_y - @cells.last.height)
|
293
304
|
end
|
@@ -303,19 +314,19 @@ module Prawn
|
|
303
314
|
#
|
304
315
|
def column_widths
|
305
316
|
@column_widths ||= begin
|
306
|
-
if width
|
317
|
+
if width - cells.min_width < -epsilon
|
307
318
|
raise Errors::CannotFit,
|
308
319
|
"Table's width was set too small to contain its contents " +
|
309
320
|
"(min width #{cells.min_width}, requested #{width})"
|
310
321
|
end
|
311
322
|
|
312
|
-
if width
|
323
|
+
if width - cells.max_width > epsilon
|
313
324
|
raise Errors::CannotFit,
|
314
325
|
"Table's width was set larger than its contents' maximum width " +
|
315
326
|
"(max width #{cells.max_width}, requested #{width})"
|
316
327
|
end
|
317
328
|
|
318
|
-
if width <
|
329
|
+
if width - natural_width < -epsilon
|
319
330
|
# Shrink the table to fit the requested width.
|
320
331
|
f = (width - cells.min_width).to_f / (natural_width - cells.min_width)
|
321
332
|
|
@@ -323,7 +334,7 @@ module Prawn
|
|
323
334
|
min, nat = column(c).min_width, column(c).width
|
324
335
|
(f * (nat - min)) + min
|
325
336
|
end
|
326
|
-
elsif width >
|
337
|
+
elsif width - natural_width > epsilon
|
327
338
|
# Expand the table to fit the requested width.
|
328
339
|
f = (width - cells.width).to_f / (cells.max_width - cells.width)
|
329
340
|
|
@@ -447,6 +458,11 @@ module Prawn
|
|
447
458
|
y_positions.each_with_index { |y, i| row(i).y = y }
|
448
459
|
end
|
449
460
|
|
461
|
+
private
|
462
|
+
|
463
|
+
def epsilon
|
464
|
+
@epsilon
|
465
|
+
end
|
450
466
|
end
|
451
467
|
|
452
468
|
|
data/lib/prawn/table/cell.rb
CHANGED
@@ -233,15 +233,39 @@ module Prawn
|
|
233
233
|
# Draws the cell onto the document. Pass in a point [x,y] to override the
|
234
234
|
# location at which the cell is drawn.
|
235
235
|
#
|
236
|
+
# If drawing a group of cells at known positions, look into
|
237
|
+
# Cell.draw_cells, which ensures that the backgrounds, borders, and
|
238
|
+
# content are all drawn in correct order so as not to overlap.
|
239
|
+
#
|
236
240
|
def draw(pt=[x, y])
|
237
|
-
|
241
|
+
self.class.draw_cells([[self, pt]])
|
242
|
+
end
|
243
|
+
|
244
|
+
# Given an array of pairs [cell, pt], draws each cell at its
|
245
|
+
# corresponding pt, making sure all backgrounds are behind all borders
|
246
|
+
# and content.
|
247
|
+
#
|
248
|
+
def self.draw_cells(cells)
|
249
|
+
cells.each do |cell, pt|
|
250
|
+
cell.set_width_constraints
|
251
|
+
cell.draw_background(pt)
|
252
|
+
end
|
238
253
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
254
|
+
cells.each do |cell, pt|
|
255
|
+
cell.draw_borders(pt)
|
256
|
+
cell.draw_bounded_content(pt)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Draws the cell's content at the point provided.
|
261
|
+
#
|
262
|
+
def draw_bounded_content(pt)
|
263
|
+
@pdf.float do
|
264
|
+
@pdf.bounding_box([pt[0] + padding_left, pt[1] - padding_top],
|
265
|
+
:width => content_width + FPTolerance,
|
266
|
+
:height => content_height + FPTolerance) do
|
267
|
+
draw_content
|
268
|
+
end
|
245
269
|
end
|
246
270
|
end
|
247
271
|
|
@@ -450,8 +474,6 @@ module Prawn
|
|
450
474
|
@border_widths[3] = val
|
451
475
|
end
|
452
476
|
|
453
|
-
protected
|
454
|
-
|
455
477
|
# Sets the cell's minimum and maximum width. Deferred until requested
|
456
478
|
# because padding and size can change.
|
457
479
|
#
|
@@ -74,8 +74,6 @@ module Prawn
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
protected
|
78
|
-
|
79
77
|
def set_width_constraints
|
80
78
|
# Sets a reasonable minimum width. If the cell has any content, make
|
81
79
|
# sure we have enough width to be at least one character wide. This is
|
@@ -85,6 +83,8 @@ module Prawn
|
|
85
83
|
super
|
86
84
|
end
|
87
85
|
|
86
|
+
protected
|
87
|
+
|
88
88
|
def with_font
|
89
89
|
@pdf.save_font do
|
90
90
|
options = {}
|
data/prawn.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Version numbering: http://wiki.github.com/sandal/prawn/development-roadmap
|
2
|
-
PRAWN_VERSION = "0.
|
2
|
+
PRAWN_VERSION = "0.12.0"
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "prawn"
|
@@ -12,16 +12,15 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.required_ruby_version = '>= 1.8.7'
|
13
13
|
spec.required_rubygems_version = ">= 1.3.6"
|
14
14
|
|
15
|
-
spec.test_files = Dir[ "
|
16
|
-
spec.
|
17
|
-
spec.extra_rdoc_files = %w{HACKING README LICENSE COPYING}
|
15
|
+
spec.test_files = Dir[ "spec/*_spec.rb" ]
|
16
|
+
spec.extra_rdoc_files = %w{README.md LICENSE COPYING GPLv2 GPLv3}
|
18
17
|
spec.rdoc_options << '--title' << 'Prawn Documentation' <<
|
19
18
|
'--main' << 'README' << '-q'
|
20
|
-
spec.authors = ["Gregory Brown","Brad Ediger","Daniel Nelson","
|
19
|
+
spec.authors = ["Gregory Brown","Brad Ediger","Daniel Nelson","Jonathan Greenberg","James Healy"]
|
21
20
|
spec.email = ["gregory.t.brown@gmail.com","brad@bradediger.com","dnelson@bluejade.com","greenberg@entryway.net","jimmy@deefa.com"]
|
22
21
|
spec.rubyforge_project = "prawn"
|
23
22
|
spec.add_dependency('pdf-reader', '>=0.9.0')
|
24
|
-
spec.add_dependency('ttfunk', '~>1.0.
|
23
|
+
spec.add_dependency('ttfunk', '~>1.0.2')
|
25
24
|
spec.homepage = "http://prawn.majesticseacreature.com"
|
26
25
|
spec.description = <<END_DESC
|
27
26
|
Prawn is a fast, tiny, and nimble PDF generator for Ruby
|
data/spec/bounding_box_spec.rb
CHANGED
@@ -87,6 +87,13 @@ describe "A bounding box" do
|
|
87
87
|
end.should.raise(ArgumentError)
|
88
88
|
end
|
89
89
|
|
90
|
+
it "should raise an ArgumentError if a block is not passed" do
|
91
|
+
pdf = Prawn::Document.new
|
92
|
+
lambda do
|
93
|
+
pdf.bounding_box([0, 0], :width => 200)
|
94
|
+
end.should.raise(ArgumentError)
|
95
|
+
end
|
96
|
+
|
90
97
|
end
|
91
98
|
|
92
99
|
describe "drawing bounding boxes" do
|
@@ -140,6 +147,44 @@ describe "drawing bounding boxes" do
|
|
140
147
|
box.height.should == 100
|
141
148
|
end
|
142
149
|
|
150
|
+
it "should advance the y-position by bbox.height by default" do
|
151
|
+
orig_y = @pdf.y
|
152
|
+
@pdf.bounding_box [0, @pdf.cursor], :width => @pdf.bounds.width,
|
153
|
+
:height => 30 do
|
154
|
+
@pdf.text "hello"
|
155
|
+
end
|
156
|
+
@pdf.y.should.be.close(orig_y - 30, 0.001)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not advance y-position if passed :hold_position => true" do
|
160
|
+
orig_y = @pdf.y
|
161
|
+
@pdf.bounding_box [0, @pdf.cursor], :width => @pdf.bounds.width,
|
162
|
+
:hold_position => true do
|
163
|
+
@pdf.text "hello"
|
164
|
+
end
|
165
|
+
# y only advances by height of one line ("hello")
|
166
|
+
@pdf.y.should.be.close(orig_y - @pdf.height_of("hello"), 0.001)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should not advance y-position of a stretchy bbox if it would stretch " +
|
170
|
+
"the bbox further" do
|
171
|
+
bottom = @pdf.y = @pdf.margin_box.absolute_bottom
|
172
|
+
@pdf.bounding_box [0, @pdf.margin_box.top], :width => @pdf.bounds.width do
|
173
|
+
@pdf.y = bottom
|
174
|
+
@pdf.text "hello" # starts a new page
|
175
|
+
end
|
176
|
+
@pdf.page_count.should == 2
|
177
|
+
|
178
|
+
# Restoring the position (to the absolute bottom) would stretch the bbox to
|
179
|
+
# the bottom of the page, which we don't want. This should be equivalent to
|
180
|
+
# a bbox with :hold_position => true, where we only advance by the amount
|
181
|
+
# that was actually drawn.
|
182
|
+
@pdf.y.should.be.close(
|
183
|
+
@pdf.margin_box.absolute_top - @pdf.height_of("hello"),
|
184
|
+
0.001
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
143
188
|
end
|
144
189
|
|
145
190
|
describe "Indentation" do
|
@@ -221,3 +266,115 @@ describe "A canvas" do
|
|
221
266
|
@pdf.y.should == 450
|
222
267
|
end
|
223
268
|
end
|
269
|
+
|
270
|
+
describe "Deep-copying" do
|
271
|
+
it "should create a new object that does not copy @document" do
|
272
|
+
Prawn::Document.new do
|
273
|
+
orig = bounds
|
274
|
+
copy = orig.deep_copy
|
275
|
+
|
276
|
+
copy.should.not == bounds
|
277
|
+
copy.document.should.be.nil
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should deep-copy parent bounds" do
|
282
|
+
Prawn::Document.new do |pdf|
|
283
|
+
outside = pdf.bounds
|
284
|
+
pdf.bounding_box [100, 100], :width => 100 do
|
285
|
+
copy = pdf.bounds.deep_copy
|
286
|
+
|
287
|
+
# the parent bounds should have the same parameters
|
288
|
+
copy.parent.width.should == outside.width
|
289
|
+
copy.parent.height.should == outside.height
|
290
|
+
|
291
|
+
# but should not be the same object
|
292
|
+
copy.parent.should.not == outside
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe "Prawn::Document#reference_bounds" do
|
299
|
+
before(:each) { create_pdf }
|
300
|
+
|
301
|
+
it "should return self for non-stretchy bounds" do
|
302
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100, :height => 100) do
|
303
|
+
@pdf.reference_bounds.should == @pdf.bounds
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should return the parent bounds if in a stretchy box" do
|
308
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100, :height => 100) do
|
309
|
+
correct_bounds = @pdf.bounds
|
310
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100) do
|
311
|
+
@pdf.reference_bounds.should == correct_bounds
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should find the non-stretchy box through 2 levels" do
|
317
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100, :height => 100) do
|
318
|
+
correct_bounds = @pdf.bounds
|
319
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100) do
|
320
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100) do
|
321
|
+
@pdf.reference_bounds.should == correct_bounds
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
it "should return the margin box if there's no explicit bbox" do
|
328
|
+
@pdf.reference_bounds.should == @pdf.margin_box
|
329
|
+
|
330
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100) do
|
331
|
+
@pdf.reference_bounds.should == @pdf.margin_box
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
it "should return the canvas box if we're in a canvas" do
|
336
|
+
@pdf.canvas do
|
337
|
+
canvas_box = @pdf.bounds
|
338
|
+
|
339
|
+
@pdf.reference_bounds.should == canvas_box
|
340
|
+
|
341
|
+
@pdf.bounding_box([0, @pdf.cursor], :width => 100) do
|
342
|
+
@pdf.reference_bounds.should == canvas_box
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
describe "BoundingBox#move_past_bottom" do
|
350
|
+
before(:each) { create_pdf }
|
351
|
+
|
352
|
+
it "should ordinarily start a new page" do
|
353
|
+
@pdf.bounds.move_past_bottom
|
354
|
+
@pdf.text "Foo"
|
355
|
+
|
356
|
+
pages = PDF::Inspector::Page.analyze(@pdf.render).pages
|
357
|
+
pages.size.should == 2
|
358
|
+
pages[0][:strings].should == []
|
359
|
+
pages[1][:strings].should == ["Foo"]
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should move to the top of the next page if it exists already" do
|
363
|
+
# save away the y-position at the top of a page
|
364
|
+
top_y = @pdf.y
|
365
|
+
|
366
|
+
# create a blank page but go to the page before it
|
367
|
+
@pdf.start_new_page
|
368
|
+
@pdf.go_to_page 1
|
369
|
+
@pdf.text "Foo"
|
370
|
+
|
371
|
+
@pdf.bounds.move_past_bottom
|
372
|
+
@pdf.y.should.be.close(top_y, 0.001) # we should be at the top
|
373
|
+
@pdf.text "Bar"
|
374
|
+
|
375
|
+
pages = PDF::Inspector::Page.analyze(@pdf.render).pages
|
376
|
+
pages.size.should == 2
|
377
|
+
pages[0][:strings].should == ["Foo"]
|
378
|
+
pages[1][:strings].should == ["Bar"]
|
379
|
+
end
|
380
|
+
end
|