prawn 2.1.0 → 2.2.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 (278) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +1 -9
  5. data/Rakefile +12 -22
  6. data/lib/prawn.rb +29 -48
  7. data/lib/prawn/document.rb +148 -123
  8. data/lib/prawn/document/bounding_box.rb +33 -26
  9. data/lib/prawn/document/column_box.rb +5 -7
  10. data/lib/prawn/document/internals.rb +6 -6
  11. data/lib/prawn/document/span.rb +20 -17
  12. data/lib/prawn/encoding.rb +65 -67
  13. data/lib/prawn/errors.rb +10 -7
  14. data/lib/prawn/font.rb +78 -62
  15. data/lib/prawn/font/afm.rb +93 -66
  16. data/lib/prawn/font/dfont.rb +2 -10
  17. data/lib/prawn/font/ttc.rb +34 -0
  18. data/lib/prawn/font/ttf.rb +73 -65
  19. data/lib/prawn/font_metric_cache.rb +9 -8
  20. data/lib/prawn/graphics.rb +110 -70
  21. data/lib/prawn/graphics/blend_mode.rb +7 -8
  22. data/lib/prawn/graphics/cap_style.rb +2 -4
  23. data/lib/prawn/graphics/color.rb +23 -26
  24. data/lib/prawn/graphics/dash.rb +22 -12
  25. data/lib/prawn/graphics/join_style.rb +8 -4
  26. data/lib/prawn/graphics/patterns.rb +185 -96
  27. data/lib/prawn/graphics/transformation.rb +11 -9
  28. data/lib/prawn/graphics/transparency.rb +15 -13
  29. data/lib/prawn/grid.rb +20 -20
  30. data/lib/prawn/image_handler.rb +4 -6
  31. data/lib/prawn/images.rb +22 -15
  32. data/lib/prawn/images/image.rb +0 -1
  33. data/lib/prawn/images/jpg.rb +26 -22
  34. data/lib/prawn/images/png.rb +60 -57
  35. data/lib/prawn/measurement_extensions.rb +8 -9
  36. data/lib/prawn/measurements.rb +14 -15
  37. data/lib/prawn/outline.rb +96 -78
  38. data/lib/prawn/repeater.rb +12 -10
  39. data/lib/prawn/security.rb +66 -48
  40. data/lib/prawn/security/arcfour.rb +1 -3
  41. data/lib/prawn/soft_mask.rb +23 -25
  42. data/lib/prawn/stamp.rb +16 -12
  43. data/lib/prawn/text.rb +59 -45
  44. data/lib/prawn/text/box.rb +9 -8
  45. data/lib/prawn/text/formatted.rb +4 -6
  46. data/lib/prawn/text/formatted/arranger.rb +51 -30
  47. data/lib/prawn/text/formatted/box.rb +112 -88
  48. data/lib/prawn/text/formatted/fragment.rb +10 -15
  49. data/lib/prawn/text/formatted/line_wrap.rb +118 -61
  50. data/lib/prawn/text/formatted/parser.rb +134 -110
  51. data/lib/prawn/text/formatted/wrap.rb +42 -32
  52. data/lib/prawn/transformation_stack.rb +3 -4
  53. data/lib/prawn/utilities.rb +6 -21
  54. data/lib/prawn/version.rb +1 -3
  55. data/lib/prawn/view.rb +4 -2
  56. data/manual/basic_concepts/adding_pages.rb +4 -7
  57. data/manual/basic_concepts/basic_concepts.rb +29 -22
  58. data/manual/basic_concepts/creation.rb +8 -11
  59. data/manual/basic_concepts/cursor.rb +2 -5
  60. data/manual/basic_concepts/measurement.rb +3 -6
  61. data/manual/basic_concepts/origin.rb +3 -6
  62. data/manual/basic_concepts/other_cursor_helpers.rb +9 -12
  63. data/manual/basic_concepts/view.rb +20 -16
  64. data/manual/bounding_box/bounding_box.rb +27 -24
  65. data/manual/bounding_box/bounds.rb +9 -12
  66. data/manual/bounding_box/canvas.rb +2 -5
  67. data/manual/bounding_box/creation.rb +4 -7
  68. data/manual/bounding_box/indentation.rb +12 -15
  69. data/manual/bounding_box/nesting.rb +22 -17
  70. data/manual/bounding_box/russian_boxes.rb +8 -9
  71. data/manual/bounding_box/stretchy.rb +10 -13
  72. data/manual/contents.rb +26 -22
  73. data/manual/cover.rb +22 -20
  74. data/manual/document_and_page_options/background.rb +9 -13
  75. data/manual/document_and_page_options/document_and_page_options.rb +23 -20
  76. data/manual/document_and_page_options/metadata.rb +16 -16
  77. data/manual/document_and_page_options/page_margins.rb +16 -20
  78. data/manual/document_and_page_options/page_size.rb +11 -12
  79. data/manual/document_and_page_options/print_scaling.rb +15 -15
  80. data/manual/example_helper.rb +2 -4
  81. data/manual/graphics/blend_mode.rb +10 -9
  82. data/manual/graphics/circle_and_ellipse.rb +2 -5
  83. data/manual/graphics/color.rb +5 -9
  84. data/manual/graphics/common_lines.rb +5 -8
  85. data/manual/graphics/fill_and_stroke.rb +2 -5
  86. data/manual/graphics/fill_rules.rb +7 -10
  87. data/manual/graphics/gradients.rb +25 -21
  88. data/manual/graphics/graphics.rb +49 -43
  89. data/manual/graphics/helper.rb +10 -9
  90. data/manual/graphics/line_width.rb +5 -7
  91. data/manual/graphics/lines_and_curves.rb +5 -8
  92. data/manual/graphics/polygon.rb +4 -8
  93. data/manual/graphics/rectangle.rb +2 -5
  94. data/manual/graphics/rotate.rb +4 -7
  95. data/manual/graphics/scale.rb +12 -15
  96. data/manual/graphics/soft_masks.rb +1 -4
  97. data/manual/graphics/stroke_cap.rb +3 -6
  98. data/manual/graphics/stroke_dash.rb +9 -12
  99. data/manual/graphics/stroke_join.rb +2 -5
  100. data/manual/graphics/translate.rb +7 -10
  101. data/manual/graphics/transparency.rb +5 -8
  102. data/manual/how_to_read_this_manual.rb +4 -6
  103. data/manual/images/absolute_position.rb +4 -7
  104. data/manual/images/fit.rb +5 -8
  105. data/manual/images/horizontal.rb +6 -9
  106. data/manual/images/images.rb +25 -23
  107. data/manual/images/plain_image.rb +3 -6
  108. data/manual/images/scale.rb +7 -10
  109. data/manual/images/vertical.rb +10 -13
  110. data/manual/images/width_and_height.rb +8 -11
  111. data/manual/layout/boxes.rb +3 -6
  112. data/manual/layout/content.rb +5 -8
  113. data/manual/layout/layout.rb +16 -16
  114. data/manual/layout/simple_grid.rb +4 -7
  115. data/manual/outline/add_subsection_to.rb +18 -21
  116. data/manual/outline/insert_section_after.rb +13 -16
  117. data/manual/outline/outline.rb +19 -17
  118. data/manual/outline/sections_and_pages.rb +15 -18
  119. data/manual/repeatable_content/alternate_page_numbering.rb +19 -17
  120. data/manual/repeatable_content/page_numbering.rb +15 -16
  121. data/manual/repeatable_content/repeatable_content.rb +23 -19
  122. data/manual/repeatable_content/repeater.rb +12 -15
  123. data/manual/repeatable_content/stamp.rb +12 -15
  124. data/manual/security/encryption.rb +7 -10
  125. data/manual/security/permissions.rb +17 -14
  126. data/manual/security/security.rb +17 -16
  127. data/manual/table.rb +2 -4
  128. data/manual/text/alignment.rb +14 -17
  129. data/manual/text/color.rb +10 -11
  130. data/manual/text/column_box.rb +5 -8
  131. data/manual/text/fallback_fonts.rb +23 -21
  132. data/manual/text/font.rb +9 -12
  133. data/manual/text/font_size.rb +11 -14
  134. data/manual/text/font_style.rb +4 -7
  135. data/manual/text/formatted_callbacks.rb +23 -21
  136. data/manual/text/formatted_text.rb +31 -25
  137. data/manual/text/free_flowing_text.rb +18 -21
  138. data/manual/text/inline.rb +16 -19
  139. data/manual/text/kerning_and_character_spacing.rb +12 -15
  140. data/manual/text/leading.rb +5 -8
  141. data/manual/text/line_wrapping.rb +33 -17
  142. data/manual/text/paragraph_indentation.rb +11 -14
  143. data/manual/text/positioned_text.rb +13 -16
  144. data/manual/text/registering_families.rb +16 -19
  145. data/manual/text/rendering_and_color.rb +7 -10
  146. data/manual/text/right_to_left_text.rb +24 -19
  147. data/manual/text/rotation.rb +26 -23
  148. data/manual/text/single_usage.rb +6 -9
  149. data/manual/text/text.rb +56 -52
  150. data/manual/text/text_box_excess.rb +18 -17
  151. data/manual/text/text_box_extensions.rb +16 -15
  152. data/manual/text/text_box_overflow.rb +15 -18
  153. data/manual/text/utf8.rb +9 -12
  154. data/manual/text/win_ansi_charset.rb +18 -19
  155. data/prawn.gemspec +37 -27
  156. data/spec/extensions/encoding_helpers.rb +0 -2
  157. data/spec/manual_spec.rb +33 -0
  158. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  159. data/spec/prawn/document/column_box_spec.rb +73 -0
  160. data/spec/prawn/document/security_spec.rb +173 -0
  161. data/spec/prawn/document_annotations_spec.rb +74 -0
  162. data/spec/prawn/document_destinations_spec.rb +13 -0
  163. data/spec/prawn/document_grid_spec.rb +96 -0
  164. data/spec/prawn/document_reference_spec.rb +25 -0
  165. data/spec/prawn/document_span_spec.rb +34 -0
  166. data/spec/prawn/document_spec.rb +751 -0
  167. data/spec/prawn/font_metric_cache_spec.rb +52 -0
  168. data/spec/prawn/font_spec.rb +513 -0
  169. data/spec/prawn/graphics/blend_mode_spec.rb +61 -0
  170. data/spec/prawn/graphics/transparency_spec.rb +79 -0
  171. data/spec/prawn/graphics_spec.rb +817 -0
  172. data/spec/prawn/graphics_stroke_styles_spec.rb +227 -0
  173. data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +13 -15
  174. data/spec/prawn/images/jpg_spec.rb +18 -0
  175. data/spec/prawn/images/png_spec.rb +281 -0
  176. data/spec/prawn/images_spec.rb +170 -0
  177. data/spec/prawn/measurements_extensions_spec.rb +22 -0
  178. data/spec/prawn/outline_spec.rb +408 -0
  179. data/spec/prawn/repeater_spec.rb +163 -0
  180. data/spec/prawn/soft_mask_spec.rb +72 -0
  181. data/spec/prawn/stamp_spec.rb +168 -0
  182. data/spec/prawn/text/box_spec.rb +1113 -0
  183. data/spec/prawn/text/formatted/arranger_spec.rb +464 -0
  184. data/spec/prawn/text/formatted/box_spec.rb +825 -0
  185. data/spec/prawn/text/formatted/fragment_spec.rb +341 -0
  186. data/spec/prawn/text/formatted/line_wrap_spec.rb +491 -0
  187. data/spec/prawn/text/formatted/parser_spec.rb +667 -0
  188. data/spec/prawn/text_draw_text_spec.rb +147 -0
  189. data/spec/prawn/text_rendering_mode_spec.rb +42 -0
  190. data/spec/prawn/text_spacing_spec.rb +93 -0
  191. data/spec/prawn/text_spec.rb +601 -0
  192. data/spec/prawn/text_with_inline_formatting_spec.rb +33 -0
  193. data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +21 -20
  194. data/spec/prawn/view_spec.rb +45 -0
  195. data/spec/spec_helper.rb +16 -16
  196. metadata +96 -151
  197. metadata.gz.sig +1 -0
  198. data/data/images/16bit.alpha +0 -0
  199. data/data/images/16bit.color +0 -0
  200. data/data/images/16bit.png +0 -0
  201. data/data/images/arrow.png +0 -0
  202. data/data/images/arrow2.png +0 -0
  203. data/data/images/blend_modes_bottom_layer.jpg +0 -0
  204. data/data/images/blend_modes_top_layer.jpg +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/indexed_transparency.png +0 -0
  213. data/data/images/indexed_transparency_alpha.dat +0 -0
  214. data/data/images/indexed_transparency_color.dat +0 -0
  215. data/data/images/letterhead.jpg +0 -0
  216. data/data/images/license.md +0 -8
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.color +0 -0
  219. data/data/images/page_white_text.png +0 -0
  220. data/data/images/pigs.jpg +0 -0
  221. data/data/images/prawn.png +0 -0
  222. data/data/images/ruport.png +0 -0
  223. data/data/images/ruport_data.dat +0 -0
  224. data/data/images/ruport_transparent.png +0 -0
  225. data/data/images/ruport_type0.png +0 -0
  226. data/data/images/stef.jpg +0 -0
  227. data/data/images/tru256.bmp +0 -0
  228. data/data/images/web-links.dat +0 -1
  229. data/data/images/web-links.png +0 -0
  230. data/data/pdfs/complex_template.pdf +0 -0
  231. data/data/pdfs/contains_ttf_font.pdf +0 -0
  232. data/data/pdfs/encrypted.pdf +0 -0
  233. data/data/pdfs/form.pdf +1 -819
  234. data/data/pdfs/hexagon.pdf +0 -61
  235. data/data/pdfs/indirect_reference.pdf +0 -86
  236. data/data/pdfs/multipage_template.pdf +0 -127
  237. data/data/pdfs/nested_pages.pdf +0 -118
  238. data/data/pdfs/page_without_mediabox.pdf +0 -193
  239. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  240. data/data/pdfs/two_hexagons.pdf +0 -90
  241. data/data/pdfs/version_1_6.pdf +0 -61
  242. data/data/shift_jis_text.txt +0 -1
  243. data/spec/acceptance/png_spec.rb +0 -35
  244. data/spec/annotations_spec.rb +0 -67
  245. data/spec/blend_mode_spec.rb +0 -71
  246. data/spec/bounding_box_spec.rb +0 -501
  247. data/spec/column_box_spec.rb +0 -59
  248. data/spec/destinations_spec.rb +0 -13
  249. data/spec/document_spec.rb +0 -738
  250. data/spec/font_metric_cache_spec.rb +0 -52
  251. data/spec/font_spec.rb +0 -475
  252. data/spec/formatted_text_arranger_spec.rb +0 -452
  253. data/spec/formatted_text_box_spec.rb +0 -716
  254. data/spec/formatted_text_fragment_spec.rb +0 -299
  255. data/spec/graphics_spec.rb +0 -705
  256. data/spec/grid_spec.rb +0 -95
  257. data/spec/images_spec.rb +0 -167
  258. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  259. data/spec/jpg_spec.rb +0 -23
  260. data/spec/line_wrap_spec.rb +0 -366
  261. data/spec/measurement_units_spec.rb +0 -22
  262. data/spec/outline_spec.rb +0 -409
  263. data/spec/png_spec.rb +0 -257
  264. data/spec/reference_spec.rb +0 -25
  265. data/spec/repeater_spec.rb +0 -154
  266. data/spec/security_spec.rb +0 -151
  267. data/spec/soft_mask_spec.rb +0 -78
  268. data/spec/span_spec.rb +0 -43
  269. data/spec/stamp_spec.rb +0 -179
  270. data/spec/stroke_styles_spec.rb +0 -208
  271. data/spec/text_at_spec.rb +0 -142
  272. data/spec/text_box_spec.rb +0 -1042
  273. data/spec/text_rendering_mode_spec.rb +0 -45
  274. data/spec/text_spacing_spec.rb +0 -93
  275. data/spec/text_spec.rb +0 -543
  276. data/spec/text_with_inline_formatting_spec.rb +0 -35
  277. data/spec/transparency_spec.rb +0 -91
  278. data/spec/view_spec.rb +0 -42
@@ -1,15 +1,14 @@
1
- # encoding: utf-8
2
- #
3
1
  # font.rb : The Prawn font class
4
2
  #
5
3
  # Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
6
4
  #
7
5
  # This is free software. Please see the LICENSE and COPYING files for details.
8
6
  #
9
- require_relative "font/afm"
10
- require_relative "font/ttf"
11
- require_relative "font/dfont"
12
- require_relative "font_metric_cache"
7
+ require_relative 'font/afm'
8
+ require_relative 'font/ttf'
9
+ require_relative 'font/dfont'
10
+ require_relative 'font/ttc'
11
+ require_relative 'font_metric_cache'
13
12
 
14
13
  module Prawn
15
14
  class Document
@@ -35,8 +34,8 @@ module Prawn
35
34
  # end
36
35
  #
37
36
  # The :name parameter must be a string. It can be one of the 14 built-in
38
- # fonts supported by PDF, or the location of a TTF file. The Font::AFM::BUILT_INS
39
- # array specifies the valid built in font values.
37
+ # fonts supported by PDF, or the location of a TTF file. The
38
+ # Font::AFM::BUILT_INS array specifies the valid built in font values.
40
39
  #
41
40
  # If a ttf font is specified, the glyphs necessary to render your document
42
41
  # will be embedded in the rendered PDF. This should be your preferred option
@@ -44,14 +43,15 @@ module Prawn
44
43
  # make it more portable.
45
44
  #
46
45
  # The options parameter is an optional hash providing size and style. To use
47
- # the :style option you need to map those font styles to their respective font files.
46
+ # the :style option you need to map those font styles to their respective
47
+ # font files.
48
48
  # See font_families for more information.
49
49
  #
50
50
  def font(name = nil, options = {})
51
- return((defined?(@font) && @font) || font("Helvetica")) if name.nil?
51
+ return((defined?(@font) && @font) || font('Helvetica')) if name.nil?
52
52
 
53
53
  if state.pages.empty? && !state.page.in_stamp_stream?
54
- fail Prawn::Errors::NotOnPage
54
+ raise Prawn::Errors::NotOnPage
55
55
  end
56
56
 
57
57
  new_font = find_font(name.to_s, options)
@@ -107,33 +107,35 @@ module Prawn
107
107
  font_size(size)
108
108
  end
109
109
 
110
- # Returns the width of the given string using the given font. If :size is not
111
- # specified as one of the options, the string is measured using the current
112
- # font size. You can also pass :kerning as an option to indicate whether
113
- # kerning should be used when measuring the width (defaults to +false+).
110
+ # Returns the width of the given string using the given font. If :size is
111
+ # not specified as one of the options, the string is measured using the
112
+ # current font size. You can also pass :kerning as an option to indicate
113
+ # whether kerning should be used when measuring the width (defaults to
114
+ # +false+).
114
115
  #
115
116
  # Note that the string _must_ be encoded properly for the font being used.
116
117
  # For AFM fonts, this is WinAnsi. For TTF, make sure the font is encoded as
117
118
  # UTF-8. You can use the Font#normalize_encoding method to make sure strings
118
119
  # are in an encoding appropriate for the current font.
119
120
  #--
120
- # For the record, this method used to be a method of Font (and still delegates
121
- # to width computations on Font). However, having the primary interface for
122
- # calculating string widths exist on Font made it tricky to write extensions
123
- # for Prawn in which widths are computed differently (e.g., taking formatting
124
- # tags into account, or the like).
125
- #
126
- # By putting width_of here, on Document itself, extensions may easily override
127
- # it and redefine the width calculation behavior.
121
+ # For the record, this method used to be a method of Font (and still
122
+ # delegates to width computations on Font). However, having the primary
123
+ # interface for calculating string widths exist on Font made it tricky to
124
+ # write extensions for Prawn in which widths are computed differently (e.g.,
125
+ # taking formatting tags into account, or the like).
126
+ #
127
+ # By putting width_of here, on Document itself, extensions may easily
128
+ # override it and redefine the width calculation behavior.
128
129
  #++
129
130
  def width_of(string, options = {})
130
- if p = options[:inline_format]
131
+ if options.key? :inline_format
132
+ p = options[:inline_format]
131
133
  p = [] unless p.is_a?(Array)
132
134
 
133
135
  # Build up an Arranger with the entire string on one line, finalize it,
134
136
  # and find its width.
135
137
  arranger = Prawn::Text::Formatted::Arranger.new(self, options)
136
- arranger.consumed = self.text_formatter.format(string, *p)
138
+ arranger.consumed = text_formatter.format(string, *p)
137
139
  arranger.finalize_line
138
140
 
139
141
  arranger.line_width
@@ -169,20 +171,26 @@ module Prawn
169
171
  #
170
172
  def font_families
171
173
  @font_families ||= {}.merge!(
172
- "Courier" => { :bold => "Courier-Bold",
173
- :italic => "Courier-Oblique",
174
- :bold_italic => "Courier-BoldOblique",
175
- :normal => "Courier" },
176
-
177
- "Times-Roman" => { :bold => "Times-Bold",
178
- :italic => "Times-Italic",
179
- :bold_italic => "Times-BoldItalic",
180
- :normal => "Times-Roman" },
181
-
182
- "Helvetica" => { :bold => "Helvetica-Bold",
183
- :italic => "Helvetica-Oblique",
184
- :bold_italic => "Helvetica-BoldOblique",
185
- :normal => "Helvetica" }
174
+ 'Courier' => {
175
+ bold: 'Courier-Bold',
176
+ italic: 'Courier-Oblique',
177
+ bold_italic: 'Courier-BoldOblique',
178
+ normal: 'Courier'
179
+ },
180
+
181
+ 'Times-Roman' => {
182
+ bold: 'Times-Bold',
183
+ italic: 'Times-Italic',
184
+ bold_italic: 'Times-BoldItalic',
185
+ normal: 'Times-Roman'
186
+ },
187
+
188
+ 'Helvetica' => {
189
+ bold: 'Helvetica-Bold',
190
+ italic: 'Helvetica-Oblique',
191
+ bold_italic: 'Helvetica-BoldOblique',
192
+ normal: 'Helvetica'
193
+ }
186
194
  )
187
195
  end
188
196
 
@@ -200,7 +208,7 @@ module Prawn
200
208
  # finishes, the original font is restored.
201
209
  #
202
210
  def save_font
203
- @font ||= find_font("Helvetica")
211
+ @font ||= find_font('Helvetica')
204
212
  original_font = @font
205
213
  original_size = @font_size
206
214
 
@@ -210,26 +218,27 @@ module Prawn
210
218
  end
211
219
 
212
220
  # Looks up the given font using the given criteria. Once a font has been
213
- # found by that matches the criteria, it will be cached to subsequent lookups
214
- # for that font will return the same object.
215
- #--
221
+ # found by that matches the criteria, it will be cached to subsequent
222
+ # lookups for that font will return the same object.
223
+ # --
216
224
  # Challenges involved: the name alone is not sufficient to uniquely identify
217
225
  # a font (think dfont suitcases that can hold multiple different fonts in a
218
226
  # single file). Thus, the :name key is included in the cache key.
219
227
  #
220
228
  # It is further complicated, however, since fonts in some formats (like the
221
229
  # dfont suitcases) can be identified either by numeric index, OR by their
222
- # name within the suitcase, and both should hash to the same font object
223
- # (to avoid the font being embedded multiple times). This is not yet implemented,
224
- # which means if someone selects a font both by name, and by index, the
225
- # font will be embedded twice. Since we do font subsetting, this double
226
- # embedding won't be catastrophic, just annoying.
230
+ # name within the suitcase, and both should hash to the same font object (to
231
+ # avoid the font being embedded multiple times). This is not yet
232
+ # implemented, which means if someone selects a font both by name, and by
233
+ # index, the font will be embedded twice. Since we do font subsetting, this
234
+ # double embedding won't be catastrophic, just annoying.
227
235
  # ++
228
236
  #
229
237
  # @private
230
238
  def find_font(name, options = {}) #:nodoc:
231
239
  if font_families.key?(name)
232
- family, name = name, font_families[name][options[:style] || :normal]
240
+ family = name
241
+ name = font_families[name][options[:style] || :normal]
233
242
  if name.is_a?(::Hash)
234
243
  options = options.merge(name)
235
244
  name = options[:file]
@@ -240,7 +249,8 @@ module Prawn
240
249
  if name.is_a? Prawn::Font
241
250
  font_registry[key] = name
242
251
  else
243
- font_registry[key] ||= Font.load(self, name, options.merge(family: family))
252
+ font_registry[key] ||=
253
+ Font.load(self, name, options.merge(family: family))
244
254
  end
245
255
  end
246
256
 
@@ -280,12 +290,14 @@ module Prawn
280
290
  attr_reader :options
281
291
 
282
292
  # Shortcut interface for constructing a font object. Filenames of the form
283
- # *.ttf will call Font::TTF.new, *.dfont Font::DFont.new, and anything else
284
- # will be passed through to Font::AFM.new()
293
+ # *.ttf will call Font::TTF.new, *.dfont Font::DFont.new, *.ttc goes to
294
+ # Font::TTC.new, and anything else will be passed through to
295
+ # Font::AFM.new()
285
296
  def self.load(document, src, options = {})
286
297
  case font_format(src, options)
287
298
  when 'ttf' then TTF.new(document, src, options)
288
299
  when 'dfont' then DFont.new(document, src, options)
300
+ when 'ttc' then TTC.new(document, src, options)
289
301
  else AFM.new(document, src, options)
290
302
  end
291
303
  end
@@ -296,16 +308,17 @@ module Prawn
296
308
  case src.to_s
297
309
  when /\.ttf$/i then return 'ttf'
298
310
  when /\.dfont$/i then return 'dfont'
311
+ when /\.ttc$/i then return 'ttc'
299
312
  else return 'afm'
300
313
  end
301
314
  end
302
315
 
303
316
  def initialize(document, name, options = {}) #:nodoc:
304
- @document = document
305
- @name = name
306
- @options = options
317
+ @document = document
318
+ @name = name
319
+ @options = options
307
320
 
308
- @family = options[:family]
321
+ @family = options[:family]
309
322
 
310
323
  @identifier = generate_unique_id
311
324
 
@@ -334,8 +347,9 @@ module Prawn
334
347
  # font. The string is expected to be UTF-8 going in. It will be re-encoded
335
348
  # and the new string will be returned. For an in-place (destructive)
336
349
  # version, see normalize_encoding!.
337
- def normalize_encoding(string)
338
- fail NotImplementedError, "subclasses of Prawn::Font must implement #normalize_encoding"
350
+ def normalize_encoding(_string)
351
+ raise NotImplementedError,
352
+ 'subclasses of Prawn::Font must implement #normalize_encoding'
339
353
  end
340
354
 
341
355
  # Destructive version of normalize_encoding; normalizes the encoding of a
@@ -364,7 +378,9 @@ module Prawn
364
378
  #
365
379
  def add_to_current_page(subset)
366
380
  @references[subset] ||= register(subset)
367
- @document.state.page.fonts.merge!(identifier_for(subset) => @references[subset])
381
+ @document.state.page.fonts.merge!(
382
+ identifier_for(subset) => @references[subset]
383
+ )
368
384
  end
369
385
 
370
386
  def identifier_for(subset) #:nodoc:
@@ -381,14 +397,14 @@ module Prawn
381
397
  # Prawn::Table::Text#styled_with_of_single_character)
382
398
  #
383
399
  def hash #:nodoc:
384
- [ self.class, self.name, self.family, size ].hash
400
+ [self.class, name, family, size].hash
385
401
  end
386
402
 
387
403
  # Compliments the #hash implementation above
388
404
  #
389
405
  def eql?(other) #:nodoc:
390
- self.class == other.class && self.name == other.name &&
391
- self.family == other.family && size == other.send(:size)
406
+ self.class == other.class && name == other.name &&
407
+ family == other.family && size == other.send(:size)
392
408
  end
393
409
 
394
410
  private
@@ -1,12 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  # prawn/font/afm.rb : Implements AFM font support for Prawn
4
2
  #
5
3
  # Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
6
4
  #
7
5
  # This is free software. Please see the LICENSE and COPYING files for details.
8
6
 
9
- require_relative "../encoding"
7
+ require_relative '../encoding'
10
8
 
11
9
  module Prawn
12
10
  class Font
@@ -19,54 +17,59 @@ module Prawn
19
17
 
20
18
  self.hide_m17n_warning = false
21
19
 
22
- BUILT_INS = %w[ Courier Helvetica Times-Roman Symbol ZapfDingbats
23
- Courier-Bold Courier-Oblique Courier-BoldOblique
24
- Times-Bold Times-Italic Times-BoldItalic
25
- Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique ]
20
+ BUILT_INS = %w[
21
+ Courier Helvetica Times-Roman Symbol ZapfDingbats
22
+ Courier-Bold Courier-Oblique Courier-BoldOblique
23
+ Times-Bold Times-Italic Times-BoldItalic
24
+ Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique
25
+ ].freeze
26
26
 
27
27
  def unicode?
28
28
  false
29
29
  end
30
30
 
31
31
  def self.metrics_path
32
- if m = ENV['METRICS']
33
- @metrics_path ||= m.split(':')
34
- else
35
- @metrics_path ||= [
36
- ".", "/usr/lib/afm",
37
- "/usr/local/lib/afm",
38
- "/usr/openwin/lib/fonts/afm",
39
- Prawn::DATADIR + '/fonts'
40
- ]
41
- end
32
+ @metrics_path ||= if ENV['METRICS']
33
+ ENV['METRICS'].split(':')
34
+ else
35
+ [
36
+ '.', '/usr/lib/afm',
37
+ '/usr/local/lib/afm',
38
+ '/usr/openwin/lib/fonts/afm',
39
+ Prawn::DATADIR + '/fonts'
40
+ ]
41
+ end
42
42
  end
43
43
 
44
44
  attr_reader :attributes #:nodoc:
45
45
 
46
+ # parse each ATM font file once only
47
+ def self.font_data
48
+ @font_data ||= SynchronizedCache.new
49
+ end
50
+
46
51
  def initialize(document, name, options = {}) #:nodoc:
47
52
  unless BUILT_INS.include?(name)
48
- fail Prawn::Errors::UnknownFont, "#{name} is not a known font."
53
+ raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
49
54
  end
50
55
 
51
56
  super
52
57
 
53
- @@font_data ||= SynchronizedCache.new # parse each ATM font file once only
54
-
55
58
  file_name = @name.dup
56
- file_name << ".afm" unless file_name =~ /\.afm$/
59
+ file_name << '.afm' unless file_name =~ /\.afm$/
57
60
  file_name = file_name[0] == '/' ? file_name : find_font(file_name)
58
61
 
59
- font_data = @@font_data[file_name] ||= parse_afm(file_name)
60
- @glyph_widths = font_data[:glyph_widths]
61
- @glyph_table = font_data[:glyph_table]
62
- @bounding_boxes = font_data[:bounding_boxes]
63
- @kern_pairs = font_data[:kern_pairs]
62
+ font_data = self.class.font_data[file_name] ||= parse_afm(file_name)
63
+ @glyph_widths = font_data[:glyph_widths]
64
+ @glyph_table = font_data[:glyph_table]
65
+ @bounding_boxes = font_data[:bounding_boxes]
66
+ @kern_pairs = font_data[:kern_pairs]
64
67
  @kern_pair_table = font_data[:kern_pair_table]
65
- @attributes = font_data[:attributes]
68
+ @attributes = font_data[:attributes]
66
69
 
67
- @ascender = @attributes["ascender"].to_i
68
- @descender = @attributes["descender"].to_i
69
- @line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
70
+ @ascender = @attributes['ascender'].to_i
71
+ @descender = @attributes['descender'].to_i
72
+ @line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
70
73
  end
71
74
 
72
75
  # The font bbox, as an array of integers
@@ -81,7 +84,7 @@ module Prawn
81
84
 
82
85
  if options[:kerning]
83
86
  strings, numbers = kern(string).partition { |e| e.is_a?(String) }
84
- total_kerning_offset = numbers.inject(0.0) { |s, r| s + r }
87
+ total_kerning_offset = numbers.inject(0.0) { |a, e| a + e }
85
88
  (unscaled_width_of(strings.join) - total_kerning_offset) * scale
86
89
  else
87
90
  unscaled_width_of(string) * scale
@@ -99,17 +102,19 @@ module Prawn
99
102
  # is replaced with a string in WinAnsi encoding.
100
103
  #
101
104
  def normalize_encoding(text)
102
- text.encode("windows-1252")
105
+ text.encode('windows-1252')
103
106
  rescue ::Encoding::InvalidByteSequenceError,
104
107
  ::Encoding::UndefinedConversionError
105
108
 
106
109
  raise Prawn::Errors::IncompatibleStringEncoding,
107
- "Your document includes text that's not compatible with the Windows-1252 character set.\n" \
108
- "If you need full UTF-8 support, use TTF fonts instead of PDF's built-in fonts\n."
110
+ "Your document includes text that's not compatible with the " \
111
+ "Windows-1252 character set.\n" \
112
+ "If you need full UTF-8 support, use TTF fonts instead of PDF's " \
113
+ "built-in fonts.\n"
109
114
  end
110
115
 
111
116
  def to_utf8(text)
112
- text.encode("UTF-8")
117
+ text.encode('UTF-8')
113
118
  end
114
119
 
115
120
  # Returns the number of characters in +str+ (a WinAnsi-encoded string).
@@ -135,45 +140,52 @@ module Prawn
135
140
  end
136
141
 
137
142
  def glyph_present?(char)
138
- !!normalize_encoding(char)
143
+ !normalize_encoding(char).nil?
139
144
  rescue Prawn::Errors::IncompatibleStringEncoding
140
145
  false
141
146
  end
142
147
 
143
148
  private
144
149
 
145
- def register(subset)
150
+ def register(_subset)
146
151
  font_dict = {
147
- :Type => :Font,
148
- :Subtype => :Type1,
149
- :BaseFont => name.to_sym
152
+ Type: :Font,
153
+ Subtype: :Type1,
154
+ BaseFont: name.to_sym
150
155
  }
151
156
 
152
157
  # Symbolic AFM fonts (Symbol, ZapfDingbats) have their own encodings
153
- font_dict.merge!(:Encoding => :WinAnsiEncoding) unless symbolic?
158
+ font_dict[:Encoding] = :WinAnsiEncoding unless symbolic?
154
159
 
155
160
  @document.ref!(font_dict)
156
161
  end
157
162
 
158
163
  def symbolic?
159
- attributes["characterset"] == "Special"
164
+ attributes['characterset'] == 'Special'
160
165
  end
161
166
 
162
167
  def find_font(file)
163
- self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } + "/#{file}"
168
+ self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
169
+ "/#{file}"
164
170
  rescue NoMethodError
165
171
  raise Prawn::Errors::UnknownFont,
166
- "Couldn't find the font: #{file} in any of:\n" + self.class.metrics_path.join("\n")
172
+ "Couldn't find the font: #{file} in any of:\n" +
173
+ self.class.metrics_path.join("\n")
167
174
  end
168
175
 
169
176
  def parse_afm(file_name)
170
- data = { :glyph_widths => {}, :bounding_boxes => {}, :kern_pairs => {}, :attributes => {} }
177
+ data = {
178
+ glyph_widths: {},
179
+ bounding_boxes: {},
180
+ kern_pairs: {},
181
+ attributes: {}
182
+ }
171
183
  section = []
172
184
 
173
185
  File.foreach(file_name) do |line|
174
186
  case line
175
187
  when /^Start(\w+)/
176
- section.push $1
188
+ section.push Regexp.last_match(1)
177
189
  next
178
190
  when /^End(\w+)/
179
191
  section.pop
@@ -181,17 +193,18 @@ module Prawn
181
193
  end
182
194
 
183
195
  case section
184
- when ["FontMetrics", "CharMetrics"]
196
+ when %w[FontMetrics CharMetrics]
185
197
  next unless line =~ /^CH?\s/
186
198
 
187
- name = line[/\bN\s+(\.?\w+)\s*;/, 1]
188
- data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
199
+ name = line[/\bN\s+(\.?\w+)\s*;/, 1]
200
+ data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
189
201
  data[:bounding_boxes][name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
190
- when ["FontMetrics", "KernData", "KernPairs"]
202
+ when %w[FontMetrics KernData KernPairs]
191
203
  next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
192
- data[:kern_pairs][[$1, $2]] = $3.to_i
193
- when ["FontMetrics", "KernData", "TrackKern"],
194
- ["FontMetrics", "Composites"]
204
+ data[:kern_pairs][[Regexp.last_match(1), Regexp.last_match(2)]] =
205
+ Regexp.last_match(3).to_i
206
+ when %w[FontMetrics KernData TrackKern],
207
+ %w[FontMetrics Composites]
195
208
  next
196
209
  else
197
210
  parse_generic_afm_attribute(line, data)
@@ -204,10 +217,15 @@ module Prawn
204
217
  data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
205
218
  end
206
219
 
207
- character_hash = Hash[Encoding::WinAnsi::CHARACTERS.zip((0..Encoding::WinAnsi::CHARACTERS.size).to_a)]
208
- data[:kern_pair_table] = data[:kern_pairs].each_with_object({}) do |p, h|
209
- h[p[0].map { |n| character_hash[n] }] = p[1]
210
- end
220
+ character_hash = Hash[
221
+ Encoding::WinAnsi::CHARACTERS.zip(
222
+ (0..Encoding::WinAnsi::CHARACTERS.size).to_a
223
+ )
224
+ ]
225
+ data[:kern_pair_table] =
226
+ data[:kern_pairs].each_with_object({}) do |p, h|
227
+ h[p[0].map { |n| character_hash[n] }] = p[1]
228
+ end
211
229
 
212
230
  data.each_value(&:freeze)
213
231
  data.freeze
@@ -215,9 +233,15 @@ module Prawn
215
233
 
216
234
  def parse_generic_afm_attribute(line, hash)
217
235
  line =~ /(^\w+)\s+(.*)/
218
- key, value = $1.to_s.downcase, $2
236
+ key = Regexp.last_match(1).to_s.downcase
237
+ value = Regexp.last_match(2)
219
238
 
220
- hash[:attributes][key] = hash[:attributes][key] ? Array(hash[:attributes][key]) << value : value
239
+ hash[:attributes][key] =
240
+ if hash[:attributes][key]
241
+ Array(hash[:attributes][key]) << value
242
+ else
243
+ value
244
+ end
221
245
  end
222
246
 
223
247
  # converts a string into an array with spacing offsets
@@ -230,7 +254,8 @@ module Prawn
230
254
  last_byte = nil
231
255
 
232
256
  string.each_byte do |byte|
233
- if k = last_byte && @kern_pair_table[[last_byte, byte]]
257
+ k = last_byte && @kern_pair_table[[last_byte, byte]]
258
+ if k
234
259
  kerned << -k << [byte]
235
260
  else
236
261
  kerned.last << byte
@@ -238,14 +263,16 @@ module Prawn
238
263
  last_byte = byte
239
264
  end
240
265
 
241
- kerned.map { |e|
242
- e = (Array === e ? e.pack("C*") : e)
243
- e.respond_to?(:force_encoding) ? e.force_encoding(::Encoding::Windows_1252) : e
244
- }
266
+ kerned.map do |e|
267
+ e = e.is_a?(Array) ? e.pack('C*') : e
268
+ if e.respond_to?(:force_encoding)
269
+ e.force_encoding(::Encoding::Windows_1252)
270
+ else
271
+ e
272
+ end
273
+ end
245
274
  end
246
275
 
247
- private
248
-
249
276
  def unscaled_width_of(string)
250
277
  string.bytes.inject(0) do |s, r|
251
278
  s + @glyph_table[r]