prawn 0.13.0 → 0.14.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +9 -0
  3. data/Gemfile +7 -14
  4. data/Rakefile +5 -10
  5. data/data/images/16bit.alpha +0 -0
  6. data/data/images/16bit.color +0 -0
  7. data/data/images/dice.alpha +0 -0
  8. data/data/images/dice.color +0 -0
  9. data/data/images/page_white_text.alpha +0 -0
  10. data/data/images/page_white_text.color +0 -0
  11. data/lib/pdf/core/document_state.rb +3 -2
  12. data/lib/pdf/core/graphics_state.rb +29 -8
  13. data/lib/pdf/core/object_store.rb +6 -15
  14. data/lib/pdf/core/pdf_object.rb +8 -33
  15. data/lib/prawn/document/bounding_box.rb +11 -0
  16. data/lib/prawn/document/column_box.rb +12 -4
  17. data/lib/prawn/document.rb +30 -42
  18. data/lib/prawn/encoding.rb +1 -2
  19. data/lib/prawn/font/afm.rb +71 -30
  20. data/lib/prawn/font/dfont.rb +1 -1
  21. data/lib/prawn/font/ttf.rb +10 -2
  22. data/lib/prawn/font.rb +7 -8
  23. data/lib/prawn/graphics.rb +8 -7
  24. data/lib/prawn/image_handler.rb +4 -0
  25. data/lib/prawn/images/jpg.rb +9 -10
  26. data/lib/prawn/images/png.rb +46 -118
  27. data/lib/prawn/images.rb +2 -7
  28. data/lib/prawn/layout.rb +2 -2
  29. data/lib/prawn/measurement_extensions.rb +1 -1
  30. data/lib/prawn/table/cells.rb +6 -2
  31. data/lib/prawn/table/column_width_calculator.rb +55 -0
  32. data/lib/prawn/table.rb +9 -22
  33. data/lib/prawn/templates.rb +75 -0
  34. data/lib/prawn/text/formatted/arranger.rb +1 -5
  35. data/lib/prawn/text/formatted/box.rb +1 -1
  36. data/lib/prawn/text/formatted/fragment.rb +5 -11
  37. data/lib/prawn/text/formatted/line_wrap.rb +4 -25
  38. data/lib/prawn/text/formatted/wrap.rb +1 -4
  39. data/lib/prawn.rb +1 -2
  40. data/manual/document_and_page_options/document_and_page_options.rb +2 -1
  41. data/manual/document_and_page_options/metadata.rb +3 -3
  42. data/manual/document_and_page_options/print_scaling.rb +20 -0
  43. data/manual/example_file.rb +2 -7
  44. data/manual/manual/cover.rb +3 -2
  45. data/manual/manual/manual.rb +1 -2
  46. data/prawn.gemspec +10 -6
  47. data/spec/bounding_box_spec.rb +12 -0
  48. data/spec/column_box_spec.rb +32 -0
  49. data/spec/document_spec.rb +5 -7
  50. data/spec/extensions/encoding_helpers.rb +2 -3
  51. data/spec/filters_spec.rb +1 -1
  52. data/spec/font_spec.rb +3 -2
  53. data/spec/formatted_text_box_spec.rb +14 -25
  54. data/spec/graphics_spec.rb +18 -0
  55. data/spec/image_handler_spec.rb +12 -0
  56. data/spec/images_spec.rb +2 -6
  57. data/spec/line_wrap_spec.rb +2 -2
  58. data/spec/object_store_spec.rb +6 -0
  59. data/spec/outline_spec.rb +10 -10
  60. data/spec/png_spec.rb +9 -12
  61. data/spec/table_spec.rb +55 -2
  62. data/spec/{template_spec.rb → template_spec_obsolete.rb} +2 -1
  63. data/spec/text_at_spec.rb +11 -26
  64. data/spec/text_box_spec.rb +6 -2
  65. data/spec/text_spec.rb +39 -27
  66. metadata +58 -38
  67. data/README.md +0 -109
  68. data/data/images/16bit.dat +0 -0
  69. data/data/images/dice.dat +0 -0
  70. data/data/images/page_white_text.dat +0 -0
  71. data/lib/prawn/compatibility.rb +0 -91
  72. data/manual/templates/full_template.rb +0 -25
  73. data/manual/templates/page_template.rb +0 -48
  74. data/manual/templates/templates.rb +0 -27
data/lib/prawn/font.rb CHANGED
@@ -6,10 +6,10 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
  #
9
- require "prawn/font/afm"
10
- require "prawn/font/ttf"
11
- require "prawn/font/dfont"
12
- require "prawn/font_metric_cache"
9
+ require_relative "font/afm"
10
+ require_relative "font/ttf"
11
+ require_relative "font/dfont"
12
+ require_relative "font_metric_cache"
13
13
 
14
14
  module Prawn
15
15
 
@@ -174,10 +174,9 @@ module Prawn
174
174
  # wish to support.
175
175
  #
176
176
  # By default the styles :bold, :italic, :bold_italic, and :normal are
177
- # defined for fonts "Courier", "Times-Roman" and "Helvetica".
178
- #
179
- # You probably want to provide those four styles, but are free to define
180
- # custom ones, like :thin, and use them in font calls.
177
+ # defined for fonts "Courier", "Times-Roman" and "Helvetica". When
178
+ # defining your own font families, you can map any or all of these
179
+ # styles to whatever font files you'd like.
181
180
  #
182
181
  def font_families
183
182
  @font_families ||= {}.merge!(
@@ -6,13 +6,14 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
- require "prawn/graphics/color"
10
- require "prawn/graphics/dash"
11
- require "prawn/graphics/cap_style"
12
- require "prawn/graphics/join_style"
13
- require "prawn/graphics/transparency"
14
- require "prawn/graphics/transformation"
15
- require "prawn/graphics/patterns"
9
+
10
+ require_relative "graphics/color"
11
+ require_relative "graphics/dash"
12
+ require_relative "graphics/cap_style"
13
+ require_relative "graphics/join_style"
14
+ require_relative "graphics/transparency"
15
+ require_relative "graphics/transformation"
16
+ require_relative "graphics/patterns"
16
17
 
17
18
  module Prawn
18
19
 
@@ -18,6 +18,10 @@ module Prawn
18
18
  @handlers.unshift handler
19
19
  end
20
20
 
21
+ def unregister(handler)
22
+ @handlers.reject!{ |h| h == handler }
23
+ end
24
+
21
25
  def find(image_blob)
22
26
  handler = @handlers.find{ |h| h.can_render? image_blob }
23
27
 
@@ -17,8 +17,7 @@ module Prawn
17
17
  attr_reader :width, :height, :bits, :channels
18
18
  attr_accessor :scaled_width, :scaled_height
19
19
 
20
- JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
21
- JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
20
+ JPEG_SOF_BLOCKS = [0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF]
22
21
 
23
22
  def self.can_render?(image_blob)
24
23
  image_blob[0, 3].unpack("C*") == [255, 216, 255]
@@ -29,22 +28,22 @@ module Prawn
29
28
  # <tt>:data</tt>:: A binary string of JPEG data
30
29
  #
31
30
  def initialize(data)
32
- @data = data.dup
33
- ruby_19 { data.force_encoding("binary") }
34
- data = StringIO.new(data)
31
+ @data = data
32
+ d = StringIO.new(@data)
33
+ d.binmode
35
34
 
36
- c_marker = "\xff" # Section marker.
37
- data.read(2) # Skip the first two bytes of JPEG identifier.
35
+ c_marker = 0xff # Section marker.
36
+ d.seek(2) # Skip the first two bytes of JPEG identifier.
38
37
  loop do
39
- marker, code, length = data.read(4).unpack('aan')
38
+ marker, code, length = d.read(4).unpack('CCn')
40
39
  raise "JPEG marker not found!" if marker != c_marker
41
40
 
42
41
  if JPEG_SOF_BLOCKS.include?(code)
43
- @bits, @height, @width, @channels = data.read(6).unpack("CnnC")
42
+ @bits, @height, @width, @channels = d.read(6).unpack("CnnC")
44
43
  break
45
44
  end
46
45
 
47
- data.read(length - 2)
46
+ d.seek(length - 2, IO::SEEK_CUR)
48
47
  end
49
48
  end
50
49
 
@@ -107,34 +107,17 @@ module Prawn
107
107
  end
108
108
  end
109
109
 
110
- # number of bits used per pixel
111
- #
112
- def pixel_bitlength
113
- if alpha_channel?
114
- self.bits * (self.colors + 1)
115
- else
116
- self.bits * self.colors
117
- end
118
- end
119
-
120
110
  # split the alpha channel data from the raw image data in images
121
111
  # where it's required.
122
112
  #
123
113
  def split_alpha_channel!
124
- unfilter_image_data if alpha_channel?
114
+ split_image_data if alpha_channel?
125
115
  end
126
116
 
127
117
  def alpha_channel?
128
118
  @color_type == 4 || @color_type == 6
129
119
  end
130
120
 
131
- # Adobe Reader can't handle 16-bit png channels -- chop off the second
132
- # byte (least significant)
133
- #
134
- def alpha_channel_bits
135
- 8
136
- end
137
-
138
121
  # Build a PDF object representing this image in +document+, and return
139
122
  # a Reference to it.
140
123
  #
@@ -180,18 +163,14 @@ module Prawn
180
163
  # append the actual image data to the object as a stream
181
164
  obj << img_data
182
165
 
183
- if alpha_channel
184
- obj.stream.compress!
185
- else
186
- obj.stream.filters << {
187
- :FlateDecode => {
188
- :Predictor => 15,
189
- :Colors => colors,
190
- :BitsPerComponent => bits,
191
- :Columns => width
192
- }
166
+ obj.stream.filters << {
167
+ :FlateDecode => {
168
+ :Predictor => 15,
169
+ :Colors => colors,
170
+ :BitsPerComponent => bits,
171
+ :Columns => width
193
172
  }
194
- end
173
+ }
195
174
 
196
175
  # sort out the colours of the image
197
176
  if palette.empty?
@@ -243,12 +222,20 @@ module Prawn
243
222
  :Subtype => :Image,
244
223
  :Height => height,
245
224
  :Width => width,
246
- :BitsPerComponent => alpha_channel_bits,
225
+ :BitsPerComponent => bits,
247
226
  :ColorSpace => :DeviceGray,
248
227
  :Decode => [0, 1]
249
228
  )
250
229
  smask_obj.stream << alpha_channel
251
- smask_obj.stream.compress!
230
+
231
+ smask_obj.stream.filters << {
232
+ :FlateDecode => {
233
+ :Predictor => 15,
234
+ :Colors => 1,
235
+ :BitsPerComponent => bits,
236
+ :Columns => width
237
+ }
238
+ }
252
239
  obj.data[:SMask] = smask_obj
253
240
  end
254
241
 
@@ -270,99 +257,40 @@ module Prawn
270
257
 
271
258
  private
272
259
 
273
- def unfilter_image_data
274
- data = @img_data.dup
260
+ def split_image_data
261
+ alpha_bytes = bits / 8
262
+ color_bytes = colors * bits / 8
275
263
 
276
- @img_data = ""
277
- @alpha_channel = ""
278
-
279
- pixel_bytes = pixel_bitlength / 8
280
- scanline_length = pixel_bytes * self.width + 1
281
- row = 0
282
- pixels = []
283
- row_data = [] # reused for each row of the image
284
- paeth, pa, pb, pc = nil
285
-
286
- data.bytes.each do |byte|
287
- # accumulate a whole scanline of bytes, and then process it all at once
288
- # we could do this with Enumerable#each_slice, but it allocates memory,
289
- # and we are trying to avoid that
290
- row_data << byte
291
- next if row_data.length < scanline_length
292
-
293
- filter = row_data.shift
294
- case filter
295
- when 0 # None
296
- when 1 # Sub
297
- row_data.each_with_index do |row_byte, index|
298
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
299
- row_data[index] = (row_byte + left) % 256
300
- end
301
- when 2 # Up
302
- row_data.each_with_index do |row_byte, index|
303
- col = (index / pixel_bytes).floor
304
- upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
305
- row_data[index] = (upper + row_byte) % 256
306
- end
307
- when 3 # Average
308
- row_data.each_with_index do |row_byte, index|
309
- col = (index / pixel_bytes).floor
310
- upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
311
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
264
+ scanline_length = (color_bytes + alpha_bytes) * self.width + 1
265
+ scanlines = @img_data.bytesize / scanline_length
266
+ pixels = self.width * self.height
312
267
 
313
- row_data[index] = (row_byte + ((left + upper)/2).floor) % 256
314
- end
315
- when 4 # Paeth
316
- left = upper = upper_left = nil
317
- row_data.each_with_index do |row_byte, index|
318
- col = (index / pixel_bytes).floor
319
-
320
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
321
- if row.zero?
322
- upper = upper_left = 0
323
- else
324
- upper = pixels[row-1][col][index % pixel_bytes]
325
- upper_left = col.zero? ? 0 :
326
- pixels[row-1][col-1][index % pixel_bytes]
327
- end
328
-
329
- p = left + upper - upper_left
330
- pa = (p - left).abs
331
- pb = (p - upper).abs
332
- pc = (p - upper_left).abs
333
-
334
- paeth = if pa <= pb && pa <= pc
335
- left
336
- elsif pb <= pc
337
- upper
338
- else
339
- upper_left
340
- end
341
-
342
- row_data[index] = (row_byte + paeth) % 256
343
- end
344
- else
345
- raise ArgumentError, "Invalid filter algorithm #{filter}"
346
- end
268
+ data = StringIO.new(@img_data)
269
+ data.binmode
347
270
 
348
- s = []
349
- row_data.each_slice pixel_bytes do |slice|
350
- s << slice
351
- end
352
- pixels << s
353
- row += 1
354
- row_data.clear
355
- end
271
+ color_data = [0x00].pack('C') * (pixels * color_bytes + scanlines)
272
+ color = StringIO.new(color_data)
273
+ color.binmode
274
+
275
+ @alpha_channel = [0x00].pack('C') * (pixels * alpha_bytes + scanlines)
276
+ alpha = StringIO.new(@alpha_channel)
277
+ alpha.binmode
356
278
 
357
- # convert the pixel data to separate strings for colours and alpha
358
- color_byte_size = self.colors * self.bits / 8
359
- alpha_byte_size = alpha_channel_bits / 8
360
- pixels.each do |this_row|
361
- this_row.each do |pixel|
362
- @img_data << pixel[0, color_byte_size].pack("C*")
363
- @alpha_channel << pixel[color_byte_size, alpha_byte_size].pack("C*")
279
+ scanlines.times do |line|
280
+ data.seek(line * scanline_length)
281
+
282
+ filter = data.getbyte
283
+
284
+ color.putc filter
285
+ alpha.putc filter
286
+
287
+ self.width.times do
288
+ color.write data.read(color_bytes)
289
+ alpha.write data.read(alpha_bytes)
364
290
  end
365
291
  end
292
+
293
+ @img_data = color_data
366
294
  end
367
295
  end
368
296
  end
data/lib/prawn/images.rb CHANGED
@@ -12,13 +12,8 @@ module Prawn
12
12
 
13
13
  module Images
14
14
  # Add the image at filename to the current page. Currently only
15
- # JPG and PNG files are supported.
16
- #
17
- # NOTE: Prawn is very slow at rendering PNGs with alpha channels, and this
18
- # uses a lot of RAM. The workaround for those who don't mind installing
19
- # RMagick is to use:
20
- #
21
- # http://github.com/amberbit/prawn-fast-png
15
+ # JPG and PNG files are supported. (Note that processing PNG
16
+ # images with alpha channels can be processor and memory intensive.)
22
17
  #
23
18
  # Arguments:
24
19
  # <tt>file</tt>:: path to file or an object that responds to #read
data/lib/prawn/layout.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "prawn/table"
2
- require 'prawn/layout/grid'
1
+ require_relative "table"
2
+ require_relative "layout/grid"
3
3
 
4
4
  module Prawn
5
5
 
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # This is free software. Please see the LICENSE and COPYING files for details.
7
7
 
8
- require 'prawn/measurements'
8
+ require_relative 'measurements'
9
9
 
10
10
  class Numeric
11
11
  include Prawn::Measurements
@@ -240,6 +240,9 @@ module Prawn
240
240
  end
241
241
  end
242
242
 
243
+ #if there are only colspanned or rowspanned cells in a table
244
+ spanned_width_needs_fixing = true
245
+
243
246
  each do |cell|
244
247
  index = cell.send(row_or_column)
245
248
  if cell.colspan > 1
@@ -251,8 +254,9 @@ module Prawn
251
254
 
252
255
  #calculate future return value
253
256
  new_sum = cell.send(meth) * cell.colspan
257
+ spanned_width_needs_fixing = (new_sum > old_sum)
254
258
 
255
- if new_sum >= old_sum
259
+ if spanned_width_needs_fixing
256
260
  #not entirely sure why we need this line, but with it the tests pass
257
261
  values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
258
262
  #overwrite the old values with the new ones, but only if all entries existed
@@ -263,7 +267,7 @@ module Prawn
263
267
  }
264
268
  end
265
269
  else
266
- if cell.class == Prawn::Table::Cell::SpanDummy
270
+ if spanned_width_needs_fixing && cell.class == Prawn::Table::Cell::SpanDummy
267
271
  values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
268
272
  end
269
273
  end
@@ -0,0 +1,55 @@
1
+ module Prawn
2
+ class Table
3
+ class ColumnWidthCalculator
4
+ def initialize(cells)
5
+ @cells = cells
6
+
7
+ @widths_by_column = Hash.new(0)
8
+ @rows_with_a_span_dummy = Hash.new(false)
9
+ end
10
+
11
+ def natural_widths
12
+ @cells.each do |cell|
13
+ @rows_with_a_span_dummy[cell.row] = true if cell.is_a?(Cell::SpanDummy)
14
+ end
15
+
16
+ #calculate natural column width for all rows that do not include a span dummy
17
+ @cells.each do |cell|
18
+ unless @rows_with_a_span_dummy[cell.row]
19
+ @widths_by_column[cell.column] =
20
+ [@widths_by_column[cell.column], cell.width.to_f].max
21
+ end
22
+ end
23
+
24
+ #integrate natural column widths for all rows that do include a span dummy
25
+ @cells.each do |cell|
26
+ next unless @rows_with_a_span_dummy[cell.row]
27
+ #the width of a SpanDummy cell will be calculated by the "mother" cell
28
+ next if cell.is_a?(Cell::SpanDummy)
29
+
30
+ if cell.colspan == 1
31
+ @widths_by_column[cell.column] =
32
+ [@widths_by_column[cell.column], cell.width.to_f].max
33
+ else
34
+ #calculate the current with of all cells that will be spanned by the current cell
35
+ current_width_of_spanned_cells =
36
+ @widths_by_column.to_a[cell.column..(cell.column + cell.colspan - 1)]
37
+ .collect{|key, value| value}.inject(0, :+)
38
+
39
+ #update the Hash only if the new with is at least equal to the old one
40
+ if cell.width.to_f > current_width_of_spanned_cells
41
+ # Split the width of colspanned cells evenly by columns
42
+ width_per_column = cell.width.to_f / cell.colspan
43
+ # Update the Hash
44
+ cell.colspan.times do |i|
45
+ @widths_by_column[cell.column + i] = width_per_column
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ @widths_by_column.sort_by { |col, _| col }.map { |_, w| w }
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/prawn/table.rb CHANGED
@@ -6,13 +6,14 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
- require 'prawn/table/cells'
10
- require 'prawn/table/cell'
11
- require 'prawn/table/cell/in_table'
12
- require 'prawn/table/cell/text'
13
- require 'prawn/table/cell/subtable'
14
- require 'prawn/table/cell/image'
15
- require 'prawn/table/cell/span_dummy'
9
+ require_relative 'table/column_width_calculator'
10
+ require_relative 'table/cells'
11
+ require_relative 'table/cell'
12
+ require_relative 'table/cell/in_table'
13
+ require_relative 'table/cell/text'
14
+ require_relative 'table/cell/subtable'
15
+ require_relative 'table/cell/image'
16
+ require_relative 'table/cell/span_dummy'
16
17
 
17
18
  module Prawn
18
19
 
@@ -549,21 +550,7 @@ module Prawn
549
550
  # Returns an array of each column's natural (unconstrained) width.
550
551
  #
551
552
  def natural_column_widths
552
- @natural_column_widths ||=
553
- begin
554
- widths_by_column = Hash.new(0)
555
- cells.each do |cell|
556
- next if cell.is_a?(Cell::SpanDummy)
557
-
558
- # Split the width of colspanned cells evenly by columns
559
- width_per_column = cell.width.to_f / cell.colspan
560
- cell.colspan.times do |i|
561
- widths_by_column[cell.column + i] =
562
- [widths_by_column[cell.column + i], width_per_column].max
563
- end
564
- end
565
- widths_by_column.sort_by { |col, _| col }.map { |_, w| w }
566
- end
553
+ @natural_column_widths ||= ColumnWidthCalculator.new(cells).natural_widths
567
554
  end
568
555
 
569
556
  # Returns the "natural" (unconstrained) width of the table. This may be
@@ -0,0 +1,75 @@
1
+ warn "Templates are no longer supported in Prawn!\n" +
2
+ "This code is for experimental testing only, and\n" +
3
+ "will extracted into its own gem in a future Prawn release"
4
+
5
+ module Prawn
6
+ module Templates
7
+ def initialize_first_page(options)
8
+ return super unless options[:template]
9
+
10
+ fresh_content_streams(options)
11
+ go_to_page(1)
12
+ end
13
+
14
+ ## FIXME: This is going to be terribly brittle because
15
+ # it copy-pastes the start_new_page method. But at least
16
+ # it should only run when templates are used.
17
+
18
+ def start_new_page(options = {})
19
+ return super unless options[:template]
20
+
21
+ if last_page = state.page
22
+ last_page_size = last_page.size
23
+ last_page_layout = last_page.layout
24
+ last_page_margins = last_page.margins
25
+ end
26
+
27
+ page_options = {:size => options[:size] || last_page_size,
28
+ :layout => options[:layout] || last_page_layout,
29
+ :margins => last_page_margins}
30
+ if last_page
31
+ new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
32
+ #erase the color space so that it gets reset on new page for fussy pdf-readers
33
+ new_graphic_state.color_space = {} if new_graphic_state
34
+ page_options.merge!(:graphic_state => new_graphic_state)
35
+ end
36
+
37
+ merge_template_options(page_options, options)
38
+
39
+ state.page = PDF::Core::Page.new(self, page_options)
40
+
41
+ apply_margin_options(options)
42
+ generate_margin_box
43
+
44
+ # Reset the bounding box if the new page has different size or layout
45
+ if last_page && (last_page.size != state.page.size ||
46
+ last_page.layout != state.page.layout)
47
+ @bounding_box = @margin_box
48
+ end
49
+
50
+ state.page.new_content_stream
51
+ use_graphic_settings(true)
52
+ forget_text_rendering_mode!
53
+
54
+ unless options[:orphan]
55
+ state.insert_page(state.page, @page_number)
56
+ @page_number += 1
57
+
58
+ canvas { image(@background, :scale => @background_scale, :at => bounds.top_left) } if @background
59
+ @y = @bounding_box.absolute_top
60
+
61
+ float do
62
+ state.on_page_create_action(self)
63
+ end
64
+ end
65
+ end
66
+
67
+ def merge_template_options(page_options, options)
68
+ object_id = state.store.import_page(options[:template], options[:template_page] || 1)
69
+ page_options.merge!(:object_id => object_id, :page_template => true)
70
+ end
71
+ end
72
+ end
73
+
74
+ Prawn::Document::VALID_OPTIONS << :template
75
+ Prawn::Document.extensions << Prawn::Templates
@@ -52,11 +52,7 @@ module Prawn
52
52
  raise "Lines must be finalized before calling #line"
53
53
  end
54
54
  @fragments.collect do |fragment|
55
- if ruby_18 { true }
56
- fragment.text
57
- else
58
- fragment.text.dup.force_encoding("utf-8")
59
- end
55
+ fragment.text.dup.force_encoding(::Encoding::UTF_8)
60
56
  end.join
61
57
  end
62
58
 
@@ -392,7 +392,7 @@ module Prawn
392
392
  # all fonts
393
393
  fallback_fonts << fragment_font
394
394
 
395
- hash[:text].unicode_characters do |char|
395
+ hash[:text].each_char do |char|
396
396
  @document.font(fragment_font)
397
397
  font_glyph_pairs << [find_font_for_this_glyph(char,
398
398
  @document.font.family,
@@ -212,11 +212,7 @@ module Prawn
212
212
  end
213
213
  case direction
214
214
  when :rtl
215
- if ruby_18 { true }
216
- string.scan(/./mu).reverse.join
217
- else
218
- string.reverse
219
- end
215
+ string.reverse
220
216
  else
221
217
  string
222
218
  end
@@ -232,11 +228,9 @@ module Prawn
232
228
 
233
229
  def process_soft_hyphens(string)
234
230
  if string.length > 0 && normalized_soft_hyphen
235
- ruby_19 {
236
- if string.encoding != normalized_soft_hyphen.encoding
237
- string.force_encoding(normalized_soft_hyphen.encoding)
238
- end
239
- }
231
+ if string.encoding != normalized_soft_hyphen.encoding
232
+ string.force_encoding(normalized_soft_hyphen.encoding)
233
+ end
240
234
  string[0..-2].gsub(normalized_soft_hyphen, "") + string[-1..-1]
241
235
  else
242
236
  string
@@ -244,7 +238,7 @@ module Prawn
244
238
  end
245
239
 
246
240
  def strip_zero_width_spaces(string)
247
- if !"".respond_to?(:encoding) || string.encoding.to_s == "UTF-8"
241
+ if string.encoding == ::Encoding::UTF_8
248
242
  string.gsub(Prawn::Text::ZWSP, "")
249
243
  else
250
244
  string