prawn 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -31
  5. data/lib/prawn.rb +1 -0
  6. data/lib/prawn/document.rb +20 -15
  7. data/lib/prawn/document/bounding_box.rb +10 -2
  8. data/lib/prawn/document/span.rb +2 -1
  9. data/lib/prawn/font.rb +6 -4
  10. data/lib/prawn/font_metric_cache.rb +7 -6
  11. data/lib/prawn/fonts/afm.rb +18 -16
  12. data/lib/prawn/fonts/ttf.rb +55 -29
  13. data/lib/prawn/graphics.rb +11 -11
  14. data/lib/prawn/graphics/color.rb +18 -16
  15. data/lib/prawn/graphics/join_style.rb +1 -1
  16. data/lib/prawn/graphics/patterns.rb +57 -49
  17. data/lib/prawn/graphics/transformation.rb +3 -3
  18. data/lib/prawn/grid.rb +36 -1
  19. data/lib/prawn/images.rb +29 -27
  20. data/lib/prawn/images/jpg.rb +4 -1
  21. data/lib/prawn/images/png.rb +2 -1
  22. data/lib/prawn/outline.rb +6 -5
  23. data/lib/prawn/repeater.rb +1 -1
  24. data/lib/prawn/security.rb +39 -36
  25. data/lib/prawn/text.rb +18 -18
  26. data/lib/prawn/text/box.rb +10 -9
  27. data/lib/prawn/text/formatted/arranger.rb +38 -19
  28. data/lib/prawn/text/formatted/box.rb +20 -15
  29. data/lib/prawn/text/formatted/line_wrap.rb +18 -16
  30. data/lib/prawn/text/formatted/parser.rb +28 -26
  31. data/lib/prawn/text/formatted/wrap.rb +15 -11
  32. data/lib/prawn/version.rb +1 -1
  33. data/lib/prawn/view.rb +2 -2
  34. data/manual/basic_concepts/measurement.rb +1 -1
  35. data/manual/bounding_box/canvas.rb +3 -3
  36. data/manual/bounding_box/nesting.rb +1 -1
  37. data/manual/document_and_page_options/background.rb +6 -2
  38. data/manual/document_and_page_options/document_and_page_options.rb +3 -3
  39. data/manual/document_and_page_options/print_scaling.rb +2 -1
  40. data/manual/graphics/common_lines.rb +1 -1
  41. data/manual/graphics/fill_and_stroke.rb +1 -1
  42. data/manual/graphics/fill_rules.rb +4 -3
  43. data/manual/graphics/helper.rb +11 -4
  44. data/manual/graphics/lines_and_curves.rb +1 -1
  45. data/manual/graphics/stroke_dash.rb +5 -5
  46. data/manual/graphics/translate.rb +2 -1
  47. data/manual/images/horizontal.rb +2 -2
  48. data/manual/images/scale.rb +3 -3
  49. data/manual/images/vertical.rb +6 -3
  50. data/manual/images/width_and_height.rb +3 -3
  51. data/manual/layout/content.rb +2 -2
  52. data/manual/outline/outline.rb +1 -1
  53. data/manual/security/permissions.rb +4 -2
  54. data/manual/security/security.rb +1 -1
  55. data/manual/text/alignment.rb +2 -2
  56. data/manual/text/column_box.rb +2 -2
  57. data/manual/text/font_style.rb +5 -2
  58. data/manual/text/formatted_callbacks.rb +17 -12
  59. data/manual/text/formatted_text.rb +7 -4
  60. data/manual/text/free_flowing_text.rb +3 -3
  61. data/manual/text/kerning_and_character_spacing.rb +4 -4
  62. data/manual/text/paragraph_indentation.rb +4 -5
  63. data/manual/text/rendering_and_color.rb +1 -1
  64. data/manual/text/right_to_left_text.rb +6 -6
  65. data/manual/text/rotation.rb +8 -3
  66. data/manual/text/text_box_extensions.rb +1 -1
  67. data/manual/text/text_box_overflow.rb +11 -9
  68. data/manual/text/win_ansi_charset.rb +9 -9
  69. data/prawn.gemspec +4 -10
  70. data/spec/prawn/document/bounding_box_spec.rb +82 -78
  71. data/spec/prawn/document/security_spec.rb +1 -1
  72. data/spec/prawn/document_span_spec.rb +14 -6
  73. data/spec/prawn/document_spec.rb +29 -26
  74. data/spec/prawn/font_spec.rb +16 -14
  75. data/spec/prawn/graphics_spec.rb +79 -44
  76. data/spec/prawn/images_spec.rb +13 -8
  77. data/spec/prawn/outline_spec.rb +127 -27
  78. data/spec/prawn/repeater_spec.rb +9 -8
  79. data/spec/prawn/soft_mask_spec.rb +1 -1
  80. data/spec/prawn/stamp_spec.rb +3 -2
  81. data/spec/prawn/text/box_spec.rb +57 -59
  82. data/spec/prawn/text/formatted/arranger_spec.rb +10 -10
  83. data/spec/prawn/text/formatted/box_spec.rb +8 -5
  84. data/spec/prawn/text/formatted/line_wrap_spec.rb +2 -1
  85. data/spec/prawn/text_draw_text_spec.rb +9 -8
  86. data/spec/prawn/text_spacing_spec.rb +2 -2
  87. data/spec/prawn/text_spec.rb +9 -9
  88. data/spec/prawn/text_with_inline_formatting_spec.rb +1 -1
  89. data/spec/prawn_manual_spec.rb +4 -4
  90. metadata +14 -98
  91. metadata.gz.sig +0 -0
@@ -212,7 +212,7 @@ module Prawn
212
212
  move_to(x + radius1, y)
213
213
 
214
214
  # Upper right hand corner
215
- curve_to [x, y + radius2],
215
+ curve_to [x, y + radius2],
216
216
  bounds: [[x + radius1, y + l2], [x + l1, y + radius2]]
217
217
 
218
218
  # Upper left hand corner
@@ -341,10 +341,8 @@ module Prawn
341
341
  }.merge(options)
342
342
 
343
343
  Prawn.verify_options(
344
- %i[
345
- at width height step_length
346
- negative_axes_length color
347
- ], options
344
+ %i[at width height step_length negative_axes_length color],
345
+ options
348
346
  )
349
347
 
350
348
  save_graphics_state do
@@ -354,11 +352,13 @@ module Prawn
354
352
  dash(1, space: 4)
355
353
  stroke_horizontal_line(
356
354
  options[:at][0] - options[:negative_axes_length],
357
- options[:at][0] + options[:width], at: options[:at][1]
355
+ options[:at][0] + options[:width],
356
+ at: options[:at][1]
358
357
  )
359
358
  stroke_vertical_line(
360
359
  options[:at][1] - options[:negative_axes_length],
361
- options[:at][1] + options[:height], at: options[:at][0]
360
+ options[:at][1] + options[:height],
361
+ at: options[:at][0]
362
362
  )
363
363
  undash
364
364
 
@@ -633,10 +633,10 @@ module Prawn
633
633
 
634
634
  ops.product(shapes).each do |operation, shape|
635
635
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
636
- def #{operation}_#{shape}(*args)
637
- #{shape}(*args)
638
- #{operation}
639
- end
636
+ def #{operation}_#{shape}(*args) # def fill_polygon(*args)
637
+ #{shape}(*args) # polygon(*args)
638
+ #{operation} # fill
639
+ end # end
640
640
  METHOD
641
641
  end
642
642
 
@@ -154,27 +154,29 @@ module Prawn
154
154
  raise ArgumentError, "unknown color space: '#{color_space}'"
155
155
  end
156
156
 
157
- operator = case type
158
- when :fill
159
- 'cs'
160
- when :stroke
161
- 'CS'
162
- else
163
- raise ArgumentError, "unknown type '#{type}'"
164
- end
157
+ operator =
158
+ case type
159
+ when :fill
160
+ 'cs'
161
+ when :stroke
162
+ 'CS'
163
+ else
164
+ raise ArgumentError, "unknown type '#{type}'"
165
+ end
165
166
 
166
167
  renderer.add_content "/#{color_space} #{operator}"
167
168
  end
168
169
 
169
170
  def set_color(type, color, options = {})
170
- operator = case type
171
- when :fill
172
- 'scn'
173
- when :stroke
174
- 'SCN'
175
- else
176
- raise ArgumentError, "unknown type '#{type}'"
177
- end
171
+ operator =
172
+ case type
173
+ when :fill
174
+ 'scn'
175
+ when :stroke
176
+ 'SCN'
177
+ else
178
+ raise ArgumentError, "unknown type '#{type}'"
179
+ end
178
180
 
179
181
  if options[:pattern]
180
182
  set_color_space type, :Pattern
@@ -28,7 +28,7 @@ module Prawn
28
28
  unless JOIN_STYLES.key?(current_join_style)
29
29
  raise Prawn::Errors::InvalidJoinStyle,
30
30
  "#{style} is not a recognized join style. Valid styles are " +
31
- JOIN_STYLES.keys.join(', ')
31
+ JOIN_STYLES.keys.join(', ')
32
32
  end
33
33
 
34
34
  write_stroke_join_style
@@ -95,14 +95,15 @@ module Prawn
95
95
  patterns["SP#{registry_key}"] = shading
96
96
  end
97
97
 
98
- operator = case type
99
- when :fill
100
- 'scn'
101
- when :stroke
102
- 'SCN'
103
- else
104
- raise ArgumentError, "unknown type '#{type}'"
105
- end
98
+ operator =
99
+ case type
100
+ when :fill
101
+ 'scn'
102
+ when :stroke
103
+ 'SCN'
104
+ else
105
+ raise ArgumentError, "unknown type '#{type}'"
106
+ end
106
107
 
107
108
  set_color_space type, :Pattern
108
109
  renderer.add_content "/SP#{registry_key} #{operator}"
@@ -113,6 +114,7 @@ module Prawn
113
114
  *arguments, from: nil, to: nil, r1: nil, r2: nil, stops: nil,
114
115
  apply_transformations: nil
115
116
  )
117
+
116
118
  case arguments.length
117
119
  when 0
118
120
  apply_transformations = true if apply_transformations.nil?
@@ -128,22 +130,23 @@ module Prawn
128
130
  raise ArgumentError, 'At least two stops must be specified'
129
131
  end
130
132
 
131
- stops = stops.map.with_index do |stop, index|
132
- case stop
133
- when Array, Hash
134
- position, color = stop
135
- else
136
- position = index / (stops.length.to_f - 1)
137
- color = stop
133
+ stops =
134
+ stops.map.with_index do |stop, index|
135
+ case stop
136
+ when Array, Hash
137
+ position, color = stop
138
+ else
139
+ position = index / (stops.length.to_f - 1)
140
+ color = stop
141
+ end
142
+
143
+ unless (0..1).cover?(position)
144
+ raise ArgumentError, 'position must be between 0 and 1'
145
+ end
146
+
147
+ GradientStop.new(position, normalize_color(color))
138
148
  end
139
149
 
140
- unless (0..1).cover?(position)
141
- raise ArgumentError, 'position must be between 0 and 1'
142
- end
143
-
144
- GradientStop.new(position, normalize_color(color))
145
- end
146
-
147
150
  if stops.first.position != 0
148
151
  raise ArgumentError, 'The first stop must have a position of 0'
149
152
  end
@@ -159,8 +162,10 @@ module Prawn
159
162
  r1 ? :radial : :axial,
160
163
  apply_transformations,
161
164
  stops,
162
- from, to,
163
- r1, r2
165
+ from,
166
+ to,
167
+ r1,
168
+ r2
164
169
  )
165
170
  end
166
171
  # rubocop: enable Metrics/ParameterLists
@@ -195,37 +200,40 @@ module Prawn
195
200
  'for more information.'
196
201
  end
197
202
 
198
- shader_stops = gradient.stops.each_cons(2).map do |first, second|
199
- ref!(
200
- FunctionType: 2,
201
- Domain: [0.0, 1.0],
202
- C0: first.color,
203
- C1: second.color,
204
- N: 1.0
205
- )
206
- end
203
+ shader_stops =
204
+ gradient.stops.each_cons(2).map do |first, second|
205
+ ref!(
206
+ FunctionType: 2,
207
+ Domain: [0.0, 1.0],
208
+ C0: first.color,
209
+ C1: second.color,
210
+ N: 1.0
211
+ )
212
+ end
207
213
 
208
214
  # If there's only two stops, we can use the single shader.
209
215
  # Otherwise we stitch the multiple shaders together.
210
- shader = if shader_stops.length == 1
211
- shader_stops.first
212
- else
213
- ref!(
214
- FunctionType: 3, # stitching function
215
- Domain: [0.0, 1.0],
216
- Functions: shader_stops,
217
- Bounds: gradient.stops[1..-2].map(&:position),
218
- Encode: [0.0, 1.0] * shader_stops.length
219
- )
220
- end
216
+ shader =
217
+ if shader_stops.length == 1
218
+ shader_stops.first
219
+ else
220
+ ref!(
221
+ FunctionType: 3, # stitching function
222
+ Domain: [0.0, 1.0],
223
+ Functions: shader_stops,
224
+ Bounds: gradient.stops[1..-2].map(&:position),
225
+ Encode: [0.0, 1.0] * shader_stops.length
226
+ )
227
+ end
221
228
 
222
229
  x1, y1, x2, y2, transformation = gradient_coordinates(gradient)
223
230
 
224
- coords = if gradient.type == :axial
225
- [0, 0, x2 - x1, y2 - y1]
226
- else
227
- [0, 0, gradient.r1, x2 - x1, y2 - y1, gradient.r2]
228
- end
231
+ coords =
232
+ if gradient.type == :axial
233
+ [0, 0, x2 - x1, y2 - y1]
234
+ else
235
+ [0, 0, gradient.r1, x2 - x1, y2 - y1, gradient.r2]
236
+ end
229
237
 
230
238
  shading = ref!(
231
239
  ShadingType: gradient.type == :axial ? 2 : 3,
@@ -48,7 +48,7 @@ module Prawn
48
48
  if options[:origin].nil?
49
49
  transformation_matrix(cos, sin, -sin, cos, 0, 0, &block)
50
50
  else
51
- raise Prawn::Errors::BlockRequired unless block_given?
51
+ raise Prawn::Errors::BlockRequired unless block
52
52
 
53
53
  x = options[:origin][0] + bounds.absolute_left
54
54
  y = options[:origin][1] + bounds.absolute_bottom
@@ -118,7 +118,7 @@ module Prawn
118
118
  if options[:origin].nil?
119
119
  transformation_matrix(factor, 0, 0, factor, 0, 0, &block)
120
120
  else
121
- raise Prawn::Errors::BlockRequired unless block_given?
121
+ raise Prawn::Errors::BlockRequired unless block
122
122
 
123
123
  x = options[:origin][0] + bounds.absolute_left
124
124
  y = options[:origin][1] + bounds.absolute_bottom
@@ -149,11 +149,11 @@ module Prawn
149
149
  raise ArgumentError,
150
150
  'Transformation matrix must have exacty 6 elements'
151
151
  end
152
- values = matrix.map { |x| x.to_f.round(5) }.join(' ')
153
152
  save_graphics_state if block_given?
154
153
 
155
154
  add_to_transformation_stack(*matrix)
156
155
 
156
+ values = PDF::Core.real_params(matrix)
157
157
  renderer.add_content "#{values} cm"
158
158
  if block_given?
159
159
  yield
@@ -56,6 +56,7 @@ module Prawn
56
56
  # @group Experimental API
57
57
  class Grid
58
58
  attr_reader :pdf, :columns, :rows, :gutter, :row_gutter, :column_gutter
59
+
59
60
  def initialize(pdf, options = {}) # :nodoc:
60
61
  valid_options = %i[columns rows gutter row_gutter column_gutter]
61
62
  Prawn.verify_options valid_options, options
@@ -213,12 +214,14 @@ module Prawn
213
214
  # A MultiBox is specified by 2 Boxes and spans the areas between.
214
215
  #
215
216
  # @group Experimental API
216
- class MultiBox < GridBox
217
+ class MultiBox
217
218
  def initialize(pdf, box1, box2)
218
219
  @pdf = pdf
219
220
  @boxes = [box1, box2]
220
221
  end
221
222
 
223
+ attr_reader :pdf
224
+
222
225
  def name
223
226
  @boxes.map(&:name).join(':')
224
227
  end
@@ -255,6 +258,38 @@ module Prawn
255
258
  bottom_box.bottom
256
259
  end
257
260
 
261
+ def top_left
262
+ [left, top]
263
+ end
264
+
265
+ def top_right
266
+ [right, top]
267
+ end
268
+
269
+ def bottom_left
270
+ [left, bottom]
271
+ end
272
+
273
+ def bottom_right
274
+ [right, bottom]
275
+ end
276
+
277
+ def bounding_box(&blk)
278
+ pdf.bounding_box(top_left, width: width, height: height, &blk)
279
+ end
280
+
281
+ def show(grid_color = 'CCCCCC')
282
+ bounding_box do
283
+ original_stroke_color = pdf.stroke_color
284
+
285
+ pdf.stroke_color = grid_color
286
+ pdf.text name
287
+ pdf.stroke_bounds
288
+
289
+ pdf.stroke_color = original_stroke_color
290
+ end
291
+ end
292
+
258
293
  private
259
294
 
260
295
  def left_box
@@ -66,10 +66,10 @@ module Prawn
66
66
  # (See also: Prawn::Images::PNG , Prawn::Images::JPG)
67
67
  #
68
68
  def image(file, options = {})
69
- Prawn.verify_options %i[
70
- at position vposition height
71
- width scale fit
72
- ], options
69
+ Prawn.verify_options(
70
+ %i[at position vposition height width scale fit],
71
+ options
72
+ )
73
73
 
74
74
  pdf_obj, info = build_image_object(file)
75
75
  embed_image(pdf_obj, info, options)
@@ -156,29 +156,31 @@ module Prawn
156
156
  def image_position(width, height, options)
157
157
  options[:position] ||= :left
158
158
 
159
- y = case options[:vposition]
160
- when :top
161
- bounds.absolute_top
162
- when :center
163
- bounds.absolute_top - (bounds.height - height) / 2.0
164
- when :bottom
165
- bounds.absolute_bottom + height
166
- when Numeric
167
- bounds.absolute_top - options[:vposition]
168
- else
169
- determine_y_with_page_flow(height)
170
- end
171
-
172
- x = case options[:position]
173
- when :left
174
- bounds.left_side
175
- when :center
176
- bounds.left_side + (bounds.width - width) / 2.0
177
- when :right
178
- bounds.right_side - width
179
- when Numeric
180
- options[:position] + bounds.left_side
181
- end
159
+ y =
160
+ case options[:vposition]
161
+ when :top
162
+ bounds.absolute_top
163
+ when :center
164
+ bounds.absolute_top - (bounds.height - height) / 2.0
165
+ when :bottom
166
+ bounds.absolute_bottom + height
167
+ when Numeric
168
+ bounds.absolute_top - options[:vposition]
169
+ else
170
+ determine_y_with_page_flow(height)
171
+ end
172
+
173
+ x =
174
+ case options[:position]
175
+ when :left
176
+ bounds.left_side
177
+ when :center
178
+ bounds.left_side + (bounds.width - width) / 2.0
179
+ when :right
180
+ bounds.right_side - width
181
+ when Numeric
182
+ options[:position] + bounds.left_side
183
+ end
182
184
 
183
185
  [x, y]
184
186
  end
@@ -16,6 +16,8 @@ module Prawn
16
16
  # of a JPG image that we need to embed them in a PDF
17
17
  #
18
18
  class JPG < Image
19
+ class FormatError < StandardError; end
20
+
19
21
  # @group Extension API
20
22
 
21
23
  attr_reader :width, :height, :bits, :channels
@@ -35,6 +37,7 @@ module Prawn
35
37
  # <tt>:data</tt>:: A binary string of JPEG data
36
38
  #
37
39
  def initialize(data)
40
+ super()
38
41
  @data = data
39
42
  d = StringIO.new(@data)
40
43
  d.binmode
@@ -43,7 +46,7 @@ module Prawn
43
46
  d.seek(2) # Skip the first two bytes of JPEG identifier.
44
47
  loop do
45
48
  marker, code, length = d.read(4).unpack('CCn')
46
- raise 'JPEG marker not found!' if marker != c_marker
49
+ raise FormatError, 'JPEG marker not found!' if marker != c_marker
47
50
 
48
51
  if JPEG_SOF_BLOCKS.include?(code)
49
52
  @bits, @height, @width, @channels = d.read(6).unpack('CnnC')
@@ -34,6 +34,7 @@ module Prawn
34
34
  # <tt>data</tt>:: A binary string of PNG data
35
35
  #
36
36
  def initialize(data)
37
+ super()
37
38
  data = StringIO.new(data.dup)
38
39
 
39
40
  data.read(8) # Skip the default header
@@ -212,7 +213,7 @@ module Prawn
212
213
  # - An array with N elements, where N is two times the number of color
213
214
  # components.
214
215
  rgb = transparency[:rgb]
215
- obj.data[:Mask] = rgb.collect { |x| [x, x] }.flatten
216
+ obj.data[:Mask] = rgb.map { |x| [x, x] }.flatten
216
217
  end
217
218
 
218
219
  # For PNG color types 4 and 6, the transparency data is stored as