prawn 2.0.2 → 2.3.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 (277) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +20 -23
  7. data/lib/prawn.rb +37 -49
  8. data/lib/prawn/document.rb +181 -133
  9. data/lib/prawn/document/bounding_box.rb +41 -29
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +18 -8
  12. data/lib/prawn/document/span.rb +21 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +115 -69
  16. data/lib/prawn/font_metric_cache.rb +14 -8
  17. data/lib/prawn/{font → fonts}/afm.rb +102 -68
  18. data/lib/prawn/{font → fonts}/dfont.rb +5 -11
  19. data/lib/prawn/fonts/otf.rb +11 -0
  20. data/lib/prawn/fonts/ttc.rb +36 -0
  21. data/lib/prawn/{font → fonts}/ttf.rb +87 -68
  22. data/lib/prawn/graphics.rb +120 -80
  23. data/lib/prawn/graphics/blend_mode.rb +65 -0
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +27 -25
  26. data/lib/prawn/graphics/dash.rb +23 -11
  27. data/lib/prawn/graphics/join_style.rb +9 -3
  28. data/lib/prawn/graphics/patterns.rb +197 -67
  29. data/lib/prawn/graphics/transformation.rb +17 -8
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +48 -47
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +39 -30
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +28 -22
  36. data/lib/prawn/images/png.rb +107 -66
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +97 -77
  40. data/lib/prawn/repeater.rb +14 -10
  41. data/lib/prawn/security.rb +81 -61
  42. data/lib/prawn/security/arcfour.rb +2 -2
  43. data/lib/prawn/soft_mask.rb +26 -26
  44. data/lib/prawn/stamp.rb +20 -13
  45. data/lib/prawn/text.rb +68 -52
  46. data/lib/prawn/text/box.rb +11 -8
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +78 -49
  49. data/lib/prawn/text/formatted/box.rb +134 -100
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +121 -63
  52. data/lib/prawn/text/formatted/parser.rb +139 -117
  53. data/lib/prawn/text/formatted/wrap.rb +43 -31
  54. data/lib/prawn/transformation_stack.rb +44 -0
  55. data/lib/prawn/utilities.rb +7 -22
  56. data/lib/prawn/version.rb +2 -2
  57. data/lib/prawn/view.rb +17 -7
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +31 -22
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +6 -7
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +22 -16
  66. data/manual/bounding_box/bounding_box.rb +29 -24
  67. data/manual/bounding_box/bounds.rb +11 -12
  68. data/manual/bounding_box/canvas.rb +4 -5
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +24 -17
  72. data/manual/bounding_box/russian_boxes.rb +14 -13
  73. data/manual/bounding_box/stretchy.rb +12 -13
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -28
  76. data/manual/document_and_page_options/background.rb +11 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +25 -20
  78. data/manual/document_and_page_options/metadata.rb +18 -16
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -12
  81. data/manual/document_and_page_options/print_scaling.rb +17 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +4 -5
  88. data/manual/graphics/fill_rules.rb +9 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -39
  91. data/manual/graphics/helper.rb +12 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +7 -8
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -7
  97. data/manual/graphics/scale.rb +14 -15
  98. data/manual/graphics/soft_masks.rb +4 -5
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +11 -12
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +9 -10
  103. data/manual/graphics/transparency.rb +7 -8
  104. data/manual/how_to_read_this_manual.rb +6 -6
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +9 -10
  108. data/manual/images/images.rb +28 -24
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +13 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +5 -6
  114. data/manual/layout/content.rb +7 -8
  115. data/manual/layout/layout.rb +18 -16
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +21 -17
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +25 -19
  124. data/manual/repeatable_content/repeater.rb +14 -15
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +9 -10
  127. data/manual/security/permissions.rb +19 -14
  128. data/manual/security/security.rb +19 -16
  129. data/manual/table.rb +3 -3
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -11
  132. data/manual/text/column_box.rb +9 -10
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +7 -8
  137. data/manual/text/formatted_callbacks.rb +25 -21
  138. data/manual/text/formatted_text.rb +33 -25
  139. data/manual/text/free_flowing_text.rb +20 -21
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +13 -14
  145. data/manual/text/positioned_text.rb +15 -16
  146. data/manual/text/registering_families.rb +20 -21
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +26 -19
  149. data/manual/text/rotation.rb +28 -23
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +57 -52
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +18 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +21 -19
  157. data/prawn.gemspec +45 -33
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +36 -0
  167. data/spec/prawn/document_spec.rb +802 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +542 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +837 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +224 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +412 -0
  180. data/spec/prawn/repeater_spec.rb +165 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +172 -0
  183. data/spec/prawn/text/box_spec.rb +1112 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +846 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +149 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -23
  198. metadata +145 -185
  199. metadata.gz.sig +4 -0
  200. data/data/images/16bit.alpha +0 -0
  201. data/data/images/16bit.color +0 -0
  202. data/data/images/16bit.png +0 -0
  203. data/data/images/arrow.png +0 -0
  204. data/data/images/arrow2.png +0 -0
  205. data/data/images/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/letterhead.jpg +0 -0
  213. data/data/images/license.md +0 -8
  214. data/data/images/page_white_text.alpha +0 -0
  215. data/data/images/page_white_text.color +0 -0
  216. data/data/images/page_white_text.png +0 -0
  217. data/data/images/pal_bk.png +0 -0
  218. data/data/images/pigs.jpg +0 -0
  219. data/data/images/prawn.png +0 -0
  220. data/data/images/ruport.png +0 -0
  221. data/data/images/ruport_data.dat +0 -0
  222. data/data/images/ruport_transparent.png +0 -0
  223. data/data/images/ruport_type0.png +0 -0
  224. data/data/images/stef.jpg +0 -0
  225. data/data/images/tru256.bmp +0 -0
  226. data/data/images/web-links.dat +0 -1
  227. data/data/images/web-links.png +0 -0
  228. data/data/pdfs/complex_template.pdf +0 -0
  229. data/data/pdfs/contains_ttf_font.pdf +0 -0
  230. data/data/pdfs/encrypted.pdf +0 -0
  231. data/data/pdfs/form.pdf +1 -819
  232. data/data/pdfs/hexagon.pdf +0 -61
  233. data/data/pdfs/indirect_reference.pdf +0 -86
  234. data/data/pdfs/multipage_template.pdf +0 -127
  235. data/data/pdfs/nested_pages.pdf +0 -118
  236. data/data/pdfs/page_without_mediabox.pdf +0 -193
  237. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  238. data/data/pdfs/two_hexagons.pdf +0 -90
  239. data/data/pdfs/version_1_6.pdf +0 -61
  240. data/data/shift_jis_text.txt +0 -1
  241. data/spec/acceptance/png.rb +0 -24
  242. data/spec/annotations_spec.rb +0 -67
  243. data/spec/bounding_box_spec.rb +0 -501
  244. data/spec/column_box_spec.rb +0 -59
  245. data/spec/destinations_spec.rb +0 -13
  246. data/spec/document_spec.rb +0 -742
  247. data/spec/extensions/mocha.rb +0 -45
  248. data/spec/font_metric_cache_spec.rb +0 -52
  249. data/spec/font_spec.rb +0 -475
  250. data/spec/formatted_text_arranger_spec.rb +0 -423
  251. data/spec/formatted_text_box_spec.rb +0 -716
  252. data/spec/formatted_text_fragment_spec.rb +0 -299
  253. data/spec/graphics_spec.rb +0 -666
  254. data/spec/grid_spec.rb +0 -95
  255. data/spec/image_handler_spec.rb +0 -53
  256. data/spec/images_spec.rb +0 -167
  257. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  258. data/spec/jpg_spec.rb +0 -23
  259. data/spec/line_wrap_spec.rb +0 -366
  260. data/spec/measurement_units_spec.rb +0 -22
  261. data/spec/outline_spec.rb +0 -409
  262. data/spec/png_spec.rb +0 -235
  263. data/spec/reference_spec.rb +0 -25
  264. data/spec/repeater_spec.rb +0 -154
  265. data/spec/security_spec.rb +0 -151
  266. data/spec/soft_mask_spec.rb +0 -78
  267. data/spec/span_spec.rb +0 -43
  268. data/spec/stamp_spec.rb +0 -179
  269. data/spec/stroke_styles_spec.rb +0 -208
  270. data/spec/text_at_spec.rb +0 -142
  271. data/spec/text_box_spec.rb +0 -1038
  272. data/spec/text_rendering_mode_spec.rb +0 -45
  273. data/spec/text_spacing_spec.rb +0 -93
  274. data/spec/text_spec.rb +0 -549
  275. data/spec/text_with_inline_formatting_spec.rb +0 -35
  276. data/spec/transparency_spec.rb +0 -91
  277. data/spec/view_spec.rb +0 -42
@@ -1,15 +1,9 @@
1
- # encoding: utf-8
2
- #
3
- # font.rb : The Prawn font class
4
- #
5
- # Copyright November 2008, Jamis Buck. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- #
1
+ # frozen_string_literal: true
2
+
9
3
  require_relative 'ttf'
10
4
 
11
5
  module Prawn
12
- class Font
6
+ module Fonts
13
7
  # @private
14
8
  class DFont < TTF
15
9
  # Returns a list of the names of all named fonts in the given dfont file.
@@ -20,7 +14,7 @@ module Prawn
20
14
  #
21
15
  def self.named_fonts(file)
22
16
  TTFunk::ResourceFile.open(file) do |f|
23
- return f.resources_for("sfnt")
17
+ return f.resources_for('sfnt')
24
18
  end
25
19
  end
26
20
 
@@ -28,7 +22,7 @@ module Prawn
28
22
  #
29
23
  def self.font_count(file)
30
24
  TTFunk::ResourceFile.open(file) do |f|
31
- return f.map["sfnt"][:list].length
25
+ return f.map['sfnt'][:list].length
32
26
  end
33
27
  end
34
28
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ttf'
4
+
5
+ module Prawn
6
+ module Fonts
7
+ # @private
8
+ class OTF < TTF
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ttf'
4
+
5
+ module Prawn
6
+ module Fonts
7
+ # @private
8
+ class TTC < TTF
9
+ # Returns a list of the names of all named fonts in the given ttc file.
10
+ # They are returned in order of their appearance in the file.
11
+ #
12
+ def self.font_names(file)
13
+ TTFunk::Collection.open(file) do |ttc|
14
+ ttc.map { |font| font.name.font_name.first }
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def read_ttf_file
21
+ TTFunk::File.from_ttc(
22
+ @name,
23
+ font_option_to_index(@name, @options[:font])
24
+ )
25
+ end
26
+
27
+ def font_option_to_index(file, option)
28
+ if option.is_a?(Numeric)
29
+ option
30
+ else
31
+ self.class.font_names(file).index { |n| n == option } || 0
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # prawn/font/ttf.rb : Implements AFM font support for Prawn
4
4
  #
@@ -11,7 +11,7 @@ require 'ttfunk'
11
11
  require 'ttfunk/subset_collection'
12
12
 
13
13
  module Prawn
14
- class Font
14
+ module Fonts
15
15
  # @private
16
16
  class TTF < Font
17
17
  attr_reader :ttf, :subsets
@@ -23,17 +23,18 @@ module Prawn
23
23
  def initialize(document, name, options = {})
24
24
  super
25
25
 
26
- @ttf = read_ttf_file
27
- @subsets = TTFunk::SubsetCollection.new(@ttf)
26
+ @ttf = read_ttf_file
27
+ @subsets = TTFunk::SubsetCollection.new(@ttf)
28
+ @italic_angle = nil
28
29
 
29
- @attributes = {}
30
- @bounding_boxes = {}
31
- @char_widths = {}
30
+ @attributes = {}
31
+ @bounding_boxes = {}
32
+ @char_widths = {}
32
33
  @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
33
34
 
34
- @ascender = Integer(@ttf.ascent * scale_factor)
35
- @descender = Integer(@ttf.descent * scale_factor)
36
- @line_gap = Integer(@ttf.line_gap * scale_factor)
35
+ @ascender = Integer(@ttf.ascent * scale_factor)
36
+ @descender = Integer(@ttf.descent * scale_factor)
37
+ @line_gap = Integer(@ttf.line_gap * scale_factor)
37
38
  end
38
39
 
39
40
  # NOTE: +string+ must be UTF8-encoded.
@@ -44,7 +45,7 @@ module Prawn
44
45
  if r.is_a?(Numeric)
45
46
  s - r
46
47
  else
47
- r.inject(s) { |s2, u| s2 + character_width_by_code(u) }
48
+ r.inject(s) { |a, e| a + character_width_by_code(e) }
48
49
  end
49
50
  end * scale
50
51
  else
@@ -61,9 +62,12 @@ module Prawn
61
62
  end
62
63
 
63
64
  # Returns true if the font has kerning data, false otherwise
65
+ #
66
+ # rubocop: disable Naming/PredicateName
64
67
  def has_kerning_data?
65
68
  @has_kerning_data
66
69
  end
70
+ # rubocop: enable Naming/PredicateName
67
71
 
68
72
  # Perform any changes to the string that need to happen
69
73
  # before it is rendered to the canvas. Returns an array of
@@ -80,7 +84,9 @@ module Prawn
80
84
  last_subset = nil
81
85
  kern(text).inject([]) do |result, element|
82
86
  if element.is_a?(Numeric)
83
- result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array)
87
+ unless result.last[1].is_a?(Array)
88
+ result.last[1] = [result.last[1]]
89
+ end
84
90
  result.last[1] << element
85
91
  result
86
92
  else
@@ -100,7 +106,7 @@ module Prawn
100
106
  end
101
107
  end
102
108
  else
103
- @subsets.encode(text.unpack("U*"))
109
+ @subsets.encode(text.unpack('U*'))
104
110
  end
105
111
  end
106
112
 
@@ -109,7 +115,7 @@ module Prawn
109
115
  end
110
116
 
111
117
  # not sure how to compute this for true-type fonts...
112
- def stemV
118
+ def stem_v
113
119
  0
114
120
  end
115
121
 
@@ -118,7 +124,8 @@ module Prawn
118
124
 
119
125
  if @ttf.postscript.exists?
120
126
  raw = @ttf.postscript.italic_angle
121
- hi, low = raw >> 16, raw & 0xFF
127
+ hi = raw >> 16
128
+ low = raw & 0xFF
122
129
  hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
123
130
  @italic_angle = "#{hi}.#{low}".to_f
124
131
  else
@@ -131,7 +138,7 @@ module Prawn
131
138
  def cap_height
132
139
  @cap_height ||= begin
133
140
  height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
134
- height == 0 ? @ascender : height
141
+ height.zero? ? @ascender : height
135
142
  end
136
143
  end
137
144
 
@@ -154,35 +161,34 @@ module Prawn
154
161
  end
155
162
 
156
163
  def pdf_flags
157
- @flags ||= begin
164
+ @pdf_flags ||= begin
158
165
  flags = 0
159
166
  flags |= 0x0001 if @ttf.postscript.fixed_pitch?
160
167
  flags |= 0x0002 if serif?
161
168
  flags |= 0x0008 if script?
162
169
  flags |= 0x0040 if italic_angle != 0
163
- flags |= 0x0004 # assume the font contains at least some non-latin characters
170
+ # Assume the font contains at least some non-latin characters
171
+ flags | 0x0004
164
172
  end
165
173
  end
166
174
 
167
175
  def normalize_encoding(text)
168
- begin
169
- text.encode(::Encoding::UTF_8)
170
- rescue => e
171
- puts e
172
- raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " \
173
- "#{text.encoding} can not be transparently converted to UTF-8. " \
174
- "Please ensure the encoding of the string you are attempting " \
175
- "to use is set correctly"
176
- end
176
+ text.encode(::Encoding::UTF_8)
177
+ rescue StandardError => e
178
+ puts e
179
+ raise Prawn::Errors::IncompatibleStringEncoding, 'Encoding ' \
180
+ "#{text.encoding} can not be transparently converted to UTF-8. " \
181
+ 'Please ensure the encoding of the string you are attempting ' \
182
+ 'to use is set correctly'
177
183
  end
178
184
 
179
185
  def to_utf8(text)
180
- text.encode("UTF-8")
186
+ text.encode('UTF-8')
181
187
  end
182
188
 
183
189
  def glyph_present?(char)
184
190
  code = char.codepoints.first
185
- cmap[code] > 0
191
+ cmap[code].positive?
186
192
  end
187
193
 
188
194
  # Returns the number of characters in +str+ (a UTF-8-encoded string).
@@ -194,7 +200,7 @@ module Prawn
194
200
  private
195
201
 
196
202
  def cmap
197
- @cmap ||= @ttf.cmap.unicode.first or fail("no unicode cmap for font")
203
+ (@cmap ||= @ttf.cmap.unicode.first) || raise('no unicode cmap for font')
198
204
  end
199
205
 
200
206
  # +string+ must be UTF8-encoded.
@@ -220,12 +226,12 @@ module Prawn
220
226
  end
221
227
 
222
228
  def kern_pairs_table
223
- @kerning_data ||= has_kerning_data? ? @ttf.kerning.tables.first.pairs : {}
224
- end
225
-
226
- def cid_to_gid_map
227
- max = cmap.code_map.keys.max
228
- (0..max).map { |cid| cmap[cid] }.pack("n*")
229
+ @kern_pairs_table ||=
230
+ if has_kerning_data?
231
+ @ttf.kerning.tables.first.pairs
232
+ else
233
+ {}
234
+ end
229
235
  end
230
236
 
231
237
  def hmtx
@@ -243,16 +249,16 @@ module Prawn
243
249
  end
244
250
 
245
251
  def scale_factor
246
- @scale ||= 1000.0 / @ttf.header.units_per_em
252
+ @scale_factor ||= 1000.0 / @ttf.header.units_per_em
247
253
  end
248
254
 
249
255
  def register(subset)
250
- temp_name = @ttf.name.postscript_name.gsub("\0", "").to_sym
251
- ref = @document.ref!(:Type => :Font, :BaseFont => temp_name)
256
+ temp_name = @ttf.name.postscript_name.delete("\0").to_sym
257
+ ref = @document.ref!(Type: :Font, BaseFont: temp_name)
252
258
 
253
259
  # Embed the font metrics in the document after everything has been
254
260
  # drawn, just before the document is emitted.
255
- @document.renderer.before_render { |doc| embed(ref, subset) }
261
+ @document.renderer.before_render { |_doc| embed(ref, subset) }
256
262
 
257
263
  ref
258
264
  end
@@ -267,29 +273,32 @@ module Prawn
267
273
 
268
274
  # empirically, it looks like Adobe Reader will not display fonts
269
275
  # if their font name is more than 33 bytes long. Strange. But true.
270
- basename = font.name.postscript_name[0, 33].gsub("\0", "")
276
+ basename = font.name.postscript_name[0, 33].delete("\0")
271
277
 
272
- fail "Can't detect a postscript name for #{file}" if basename.nil?
278
+ raise "Can't detect a postscript name for #{file}" if basename.nil?
273
279
 
274
- fontfile = @document.ref!(:Length1 => font_content.size)
280
+ fontfile = @document.ref!(Length1: font_content.size)
275
281
  fontfile.stream << font_content
276
282
  fontfile.stream.compress!
277
283
 
278
- descriptor = @document.ref!(:Type => :FontDescriptor,
279
- :FontName => basename.to_sym,
280
- :FontFile2 => fontfile,
281
- :FontBBox => bbox,
282
- :Flags => pdf_flags,
283
- :StemV => stemV,
284
- :ItalicAngle => italic_angle,
285
- :Ascent => @ascender,
286
- :Descent => @descender,
287
- :CapHeight => cap_height,
288
- :XHeight => x_height)
284
+ descriptor = @document.ref!(
285
+ Type: :FontDescriptor,
286
+ FontName: basename.to_sym,
287
+ FontFile2: fontfile,
288
+ FontBBox: bbox,
289
+ Flags: pdf_flags,
290
+ StemV: stem_v,
291
+ ItalicAngle: italic_angle,
292
+ Ascent: @ascender,
293
+ Descent: @descender,
294
+ CapHeight: cap_height,
295
+ XHeight: x_height
296
+ )
289
297
 
290
298
  hmtx = font.horizontal_metrics
291
- widths = font.cmap.tables.first.code_map.map { |gid|
292
- Integer(hmtx.widths[gid] * scale_factor) }[32..-1]
299
+ widths = font.cmap.tables.first.code_map.map do |gid|
300
+ Integer(hmtx.widths[gid] * scale_factor)
301
+ end[32..-1]
293
302
 
294
303
  # It would be nice to have Encoding set for the macroman subsets,
295
304
  # and only do a ToUnicode cmap for non-encoded unicode subsets.
@@ -304,14 +313,22 @@ module Prawn
304
313
  map = @subsets[subset].to_unicode_map
305
314
 
306
315
  ranges = [[]]
307
- map.keys.sort.inject("") do |s, code|
316
+ map.keys.sort.inject('') do |_s, code|
308
317
  ranges << [] if ranges.last.length >= 100
309
318
  unicode = map[code]
310
- ranges.last << "<%02x><%04x>" % [code, unicode]
319
+ ranges.last << format(
320
+ '<%<code>02x><%<unicode>04x>',
321
+ code: code,
322
+ unicode: unicode
323
+ )
311
324
  end
312
325
 
313
- range_blocks = ranges.inject("") do |s, list|
314
- s << "%d beginbfchar\n%s\nendbfchar\n" % [list.length, list.join("\n")]
326
+ range_blocks = ranges.inject(+'') do |s, list|
327
+ s << format(
328
+ "%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
329
+ lenght: list.length,
330
+ list: list.join("\n")
331
+ )
315
332
  end
316
333
 
317
334
  to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
@@ -320,16 +337,18 @@ module Prawn
320
337
  cmap << to_unicode_cmap
321
338
  cmap.stream.compress!
322
339
 
323
- reference.data.update(:Subtype => :TrueType,
324
- :BaseFont => basename.to_sym,
325
- :FontDescriptor => descriptor,
326
- :FirstChar => 32,
327
- :LastChar => 255,
328
- :Widths => @document.ref!(widths),
329
- :ToUnicode => cmap)
340
+ reference.data.update(
341
+ Subtype: :TrueType,
342
+ BaseFont: basename.to_sym,
343
+ FontDescriptor: descriptor,
344
+ FirstChar: 32,
345
+ LastChar: 255,
346
+ Widths: @document.ref!(widths),
347
+ ToUnicode: cmap
348
+ )
330
349
  end
331
350
 
332
- UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, "")
351
+ UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, '')
333
352
  /CIDInit /ProcSet findresource begin
334
353
  12 dict begin
335
354
  begincmap
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # graphics.rb : Implements PDF drawing primitives
4
4
  #
@@ -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_relative "graphics/color"
10
- require_relative "graphics/dash"
11
- require_relative "graphics/cap_style"
12
- require_relative "graphics/join_style"
13
- require_relative "graphics/transparency"
14
- require_relative "graphics/transformation"
15
- require_relative "graphics/patterns"
9
+ require_relative 'graphics/blend_mode'
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
  # Implements the drawing facilities for Prawn::Document.
@@ -22,6 +23,7 @@ module Prawn
22
23
  # ruby-pdf.rubyforge.org
23
24
  #
24
25
  module Graphics
26
+ include BlendMode
25
27
  include Color
26
28
  include Dash
27
29
  include CapStyle
@@ -64,9 +66,11 @@ module Prawn
64
66
  # pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
65
67
  #
66
68
  def curve_to(dest, options = {})
67
- options[:bounds] or fail Prawn::Errors::InvalidGraphicsPath,
68
- "Bounding points for bezier curve must be specified " \
69
- "as :bounds => [[x1,y1],[x2,y2]]"
69
+ options[:bounds] || raise(
70
+ Prawn::Errors::InvalidGraphicsPath,
71
+ 'Bounding points for bezier curve must be specified ' \
72
+ 'as :bounds => [[x1,y1],[x2,y2]]'
73
+ )
70
74
 
71
75
  curve_points = PDF::Core.real_params(
72
76
  (options[:bounds] << dest).flat_map { |e| map_to_absolute(e) }
@@ -95,7 +99,9 @@ module Prawn
95
99
  #
96
100
  def rounded_rectangle(point, width, height, radius)
97
101
  x, y = point
98
- rounded_polygon(radius, point, [x + width, y], [x + width, y - height], [x, y - height])
102
+ rounded_polygon(
103
+ radius, point, [x + width, y], [x + width, y - height], [x, y - height]
104
+ )
99
105
  end
100
106
 
101
107
  ###########################################################
@@ -144,11 +150,7 @@ module Prawn
144
150
  # horizontal_line 25, 100, :at => 75
145
151
  #
146
152
  def horizontal_line(x1, x2, options = {})
147
- if options[:at]
148
- y1 = options[:at]
149
- else
150
- y1 = y - bounds.absolute_bottom
151
- end
153
+ y1 = options[:at] || y - bounds.absolute_bottom
152
154
 
153
155
  line(x1, y1, x2, y1)
154
156
  end
@@ -184,9 +186,9 @@ module Prawn
184
186
  #
185
187
  KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
186
188
 
187
- # Draws a circle of radius <tt>radius</tt> with the centre-point at <tt>point</tt>
188
- # as a complete subpath. The drawing point will be moved to the
189
- # centre-point upon completion of the drawing the circle.
189
+ # Draws a circle of radius <tt>radius</tt> with the centre-point at
190
+ # <tt>point</tt> as a complete subpath. The drawing point will be moved to
191
+ # the centre-point upon completion of the drawing the circle.
190
192
  #
191
193
  # pdf.circle [100,100], 25
192
194
  #
@@ -194,36 +196,36 @@ module Prawn
194
196
  ellipse(center, radius, radius)
195
197
  end
196
198
 
197
- # Draws an ellipse of +x+ radius <tt>r1</tt> and +y+ radius <tt>r2</tt>
198
- # with the centre-point at <tt>point</tt> as a complete subpath. The
199
- # drawing point will be moved to the centre-point upon completion of the
200
- # drawing the ellipse.
199
+ # Draws an ellipse of +x+ radius <tt>radius1</tt> and +y+ radius
200
+ # <tt>radius2</tt> with the centre-point at <tt>point</tt> as a complete
201
+ # subpath. The drawing point will be moved to the centre-point upon
202
+ # completion of the drawing the ellipse.
201
203
  #
202
204
  # # draws an ellipse with x-radius 25 and y-radius 50
203
205
  # pdf.ellipse [100,100], 25, 50
204
206
  #
205
- def ellipse(point, r1, r2 = r1)
207
+ def ellipse(point, radius1, radius2 = radius1)
206
208
  x, y = point
207
- l1 = r1 * KAPPA
208
- l2 = r2 * KAPPA
209
+ l1 = radius1 * KAPPA
210
+ l2 = radius2 * KAPPA
209
211
 
210
- move_to(x + r1, y)
212
+ move_to(x + radius1, y)
211
213
 
212
214
  # Upper right hand corner
213
- curve_to [x, y + r2],
214
- :bounds => [[x + r1, y + l2], [x + l1, y + r2]]
215
+ curve_to [x, y + radius2],
216
+ bounds: [[x + radius1, y + l2], [x + l1, y + radius2]]
215
217
 
216
218
  # Upper left hand corner
217
- curve_to [x - r1, y],
218
- :bounds => [[x - l1, y + r2], [x - r1, y + l2]]
219
+ curve_to [x - radius1, y],
220
+ bounds: [[x - l1, y + radius2], [x - radius1, y + l2]]
219
221
 
220
222
  # Lower left hand corner
221
- curve_to [x, y - r2],
222
- :bounds => [[x - r1, y - l2], [x - l1, y - r2]]
223
+ curve_to [x, y - radius2],
224
+ bounds: [[x - radius1, y - l2], [x - l1, y - radius2]]
223
225
 
224
226
  # Lower right hand corner
225
- curve_to [x + r1, y],
226
- :bounds => [[x + l1, y - r2], [x + r1, y - l2]]
227
+ curve_to [x + radius1, y],
228
+ bounds: [[x + l1, y - radius2], [x + radius1, y - l2]]
227
229
 
228
230
  move_to(x, y)
229
231
  end
@@ -239,35 +241,47 @@ module Prawn
239
241
  line_to(*point)
240
242
  end
241
243
  # close the path
242
- renderer.add_content "h"
244
+ renderer.add_content 'h'
243
245
  end
244
246
 
245
- # Draws a rounded polygon from specified points using the radius to define bezier curves
247
+ # Draws a rounded polygon from specified points using the radius to define
248
+ # bezier curves
246
249
  #
247
- # # draws a rounded filled in polygon
248
- # pdf.fill_and_stroke_rounded_polygon(10, [100, 250], [200, 300], [300, 250],
249
- # [300, 150], [200, 100], [100, 150])
250
+ # # draws a rounded filled in polygon
251
+ # pdf.fill_and_stroke_rounded_polygon(
252
+ # 10, [100, 250], [200, 300], [300, 250], [300, 150], [200, 100],
253
+ # [100, 150]
254
+ # )
250
255
  def rounded_polygon(radius, *points)
251
256
  move_to point_on_line(radius, points[1], points[0])
252
257
  sides = points.size
253
258
  points << points[0] << points[1]
254
- (sides).times do |i|
259
+ sides.times do |i|
255
260
  rounded_vertex(radius, points[i], points[i + 1], points[i + 2])
256
261
  end
257
262
  # close the path
258
- renderer.add_content "h"
263
+ renderer.add_content 'h'
259
264
  end
260
265
 
261
- # Creates a rounded vertex for a line segment used for building a rounded polygon
262
- # requires a radius to define bezier curve and three points. The first two points define
263
- # the line segment and the third point helps define the curve for the vertex.
266
+ # Creates a rounded vertex for a line segment used for building a rounded
267
+ # polygon requires a radius to define bezier curve and three points. The
268
+ # first two points define the line segment and the third point helps define
269
+ # the curve for the vertex.
264
270
  def rounded_vertex(radius, *points)
265
- radial_point_1 = point_on_line(radius, points[0], points[1])
266
- bezier_point_1 = point_on_line((radius - radius * KAPPA), points[0], points[1])
267
- radial_point_2 = point_on_line(radius, points[2], points[1])
268
- bezier_point_2 = point_on_line((radius - radius * KAPPA), points[2], points[1])
269
- line_to(radial_point_1)
270
- curve_to(radial_point_2, :bounds => [bezier_point_1, bezier_point_2])
271
+ radial_point1 = point_on_line(radius, points[0], points[1])
272
+ bezier_point1 = point_on_line(
273
+ (radius - radius * KAPPA),
274
+ points[0],
275
+ points[1]
276
+ )
277
+ radial_point2 = point_on_line(radius, points[2], points[1])
278
+ bezier_point2 = point_on_line(
279
+ (radius - radius * KAPPA),
280
+ points[2],
281
+ points[1]
282
+ )
283
+ line_to(radial_point1)
284
+ curve_to(radial_point2, bounds: [bezier_point1, bezier_point2])
271
285
  end
272
286
 
273
287
  # Strokes the current path. If a block is provided, yields to the block
@@ -275,7 +289,7 @@ module Prawn
275
289
  #
276
290
  def stroke
277
291
  yield if block_given?
278
- renderer.add_content "S"
292
+ renderer.add_content 'S'
279
293
  end
280
294
 
281
295
  # Closes and strokes the current path. If a block is provided, yields to
@@ -283,7 +297,7 @@ module Prawn
283
297
  #
284
298
  def close_and_stroke
285
299
  yield if block_given?
286
- renderer.add_content "s"
300
+ renderer.add_content 's'
287
301
  end
288
302
 
289
303
  # Draws and strokes a rectangle represented by the current bounding box
@@ -318,38 +332,56 @@ module Prawn
318
332
  #
319
333
  def stroke_axis(options = {})
320
334
  options = {
321
- :at => [0, 0],
322
- :height => bounds.height.to_i - (options[:at] || [0, 0])[1],
323
- :width => bounds.width.to_i - (options[:at] || [0, 0])[0],
324
- :step_length => 100,
325
- :negative_axes_length => 20,
326
- :color => "000000"
335
+ at: [0, 0],
336
+ height: bounds.height.to_i - (options[:at] || [0, 0])[1],
337
+ width: bounds.width.to_i - (options[:at] || [0, 0])[0],
338
+ step_length: 100,
339
+ negative_axes_length: 20,
340
+ color: '000000'
327
341
  }.merge(options)
328
342
 
329
- Prawn.verify_options([:at, :width, :height, :step_length,
330
- :negative_axes_length, :color], options)
343
+ Prawn.verify_options(
344
+ %i[
345
+ at width height step_length
346
+ negative_axes_length color
347
+ ], options
348
+ )
331
349
 
332
350
  save_graphics_state do
333
351
  fill_color(options[:color])
334
352
  stroke_color(options[:color])
335
353
 
336
- dash(1, :space => 4)
337
- stroke_horizontal_line(options[:at][0] - options[:negative_axes_length],
338
- options[:at][0] + options[:width], :at => options[:at][1])
339
- stroke_vertical_line(options[:at][1] - options[:negative_axes_length],
340
- options[:at][1] + options[:height], :at => options[:at][0])
354
+ dash(1, space: 4)
355
+ stroke_horizontal_line(
356
+ options[:at][0] - options[:negative_axes_length],
357
+ options[:at][0] + options[:width], at: options[:at][1]
358
+ )
359
+ stroke_vertical_line(
360
+ options[:at][1] - options[:negative_axes_length],
361
+ options[:at][1] + options[:height], at: options[:at][0]
362
+ )
341
363
  undash
342
364
 
343
365
  fill_circle(options[:at], 1)
344
366
 
345
- (options[:step_length]..options[:width]).step(options[:step_length]) do |point|
367
+ (options[:step_length]..options[:width])
368
+ .step(options[:step_length]) do |point|
346
369
  fill_circle([options[:at][0] + point, options[:at][1]], 1)
347
- draw_text(point, :at => [options[:at][0] + point - 5, options[:at][1] - 10], :size => 7)
370
+ draw_text(
371
+ point,
372
+ at: [options[:at][0] + point - 5, options[:at][1] - 10],
373
+ size: 7
374
+ )
348
375
  end
349
376
 
350
- (options[:step_length]..options[:height]).step(options[:step_length]) do |point|
377
+ (options[:step_length]..options[:height])
378
+ .step(options[:step_length]) do |point|
351
379
  fill_circle([options[:at][0], options[:at][1] + point], 1)
352
- draw_text(point, :at => [options[:at][0] - 17, options[:at][1] + point - 2], :size => 7)
380
+ draw_text(
381
+ point,
382
+ at: [options[:at][0] - 17, options[:at][1] + point - 2],
383
+ size: 7
384
+ )
353
385
  end
354
386
  end
355
387
  end
@@ -363,7 +395,7 @@ module Prawn
363
395
  #
364
396
  def fill(options = {})
365
397
  yield if block_given?
366
- renderer.add_content(options[:fill_rule] == :even_odd ? "f*" : "f")
398
+ renderer.add_content(options[:fill_rule] == :even_odd ? 'f*' : 'f')
367
399
  end
368
400
 
369
401
  # Closes, fills, and strokes the current path. If a block is provided,
@@ -377,13 +409,13 @@ module Prawn
377
409
  #
378
410
  def fill_and_stroke(options = {})
379
411
  yield if block_given?
380
- renderer.add_content(options[:fill_rule] == :even_odd ? "b*" : "b")
412
+ renderer.add_content(options[:fill_rule] == :even_odd ? 'b*' : 'b')
381
413
  end
382
414
 
383
415
  # Closes the current path.
384
416
  #
385
417
  def close_path
386
- renderer.add_content "h"
418
+ renderer.add_content 'h'
387
419
  end
388
420
 
389
421
  ##
@@ -592,12 +624,20 @@ module Prawn
592
624
  # :call-seq:
593
625
  # fill_and_stroke_rounded_polygon(radius, *points)
594
626
 
595
- ops = %w{fill stroke fill_and_stroke}
596
- shapes = %w{line_to curve_to rectangle rounded_rectangle line horizontal_line horizontal_rule vertical_line
597
- curve circle_at circle ellipse_at ellipse polygon rounded_polygon rounded_vertex}
627
+ ops = %w[fill stroke fill_and_stroke]
628
+ shapes = %w[
629
+ line_to curve_to rectangle rounded_rectangle line horizontal_line
630
+ horizontal_rule vertical_line curve circle_at circle ellipse_at ellipse
631
+ polygon rounded_polygon rounded_vertex
632
+ ]
598
633
 
599
634
  ops.product(shapes).each do |operation, shape|
600
- class_eval "def #{operation}_#{shape}(*args); #{shape}(*args); #{operation}; end"
635
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
636
+ def #{operation}_#{shape}(*args)
637
+ #{shape}(*args)
638
+ #{operation}
639
+ end
640
+ METHOD
601
641
  end
602
642
 
603
643
  private
@@ -627,8 +667,8 @@ module Prawn
627
667
  angle * Math::PI / 180
628
668
  end
629
669
 
630
- # Returns the coordinates for a point on a line that is a given distance away from the second
631
- # point defining the line segement
670
+ # Returns the coordinates for a point on a line that is a given distance
671
+ # away from the second point defining the line segement
632
672
  def point_on_line(distance_from_end, *points)
633
673
  x0, y0, x1, y1 = points.flatten
634
674
  length = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2)