prawn 2.3.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/prawn/document/bounding_box.rb +223 -143
  4. data/lib/prawn/document/column_box.rb +61 -26
  5. data/lib/prawn/document/internals.rb +25 -16
  6. data/lib/prawn/document/span.rb +21 -18
  7. data/lib/prawn/document.rb +273 -182
  8. data/lib/prawn/encoding.rb +2 -5
  9. data/lib/prawn/errors.rb +23 -34
  10. data/lib/prawn/font.rb +254 -139
  11. data/lib/prawn/font_metric_cache.rb +18 -16
  12. data/lib/prawn/fonts/afm.rb +99 -57
  13. data/lib/prawn/fonts/dfont.rb +7 -1
  14. data/lib/prawn/fonts/otf.rb +4 -1
  15. data/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
  16. data/lib/prawn/fonts/ttc.rb +7 -2
  17. data/lib/prawn/fonts/ttf.rb +345 -107
  18. data/lib/prawn/fonts.rb +14 -0
  19. data/lib/prawn/graphics/blend_mode.rb +25 -28
  20. data/lib/prawn/graphics/cap_style.rb +9 -12
  21. data/lib/prawn/graphics/color.rb +75 -50
  22. data/lib/prawn/graphics/dash.rb +45 -42
  23. data/lib/prawn/graphics/join_style.rb +18 -12
  24. data/lib/prawn/graphics/patterns.rb +239 -110
  25. data/lib/prawn/graphics/transformation.rb +51 -44
  26. data/lib/prawn/graphics/transparency.rb +16 -40
  27. data/lib/prawn/graphics.rb +370 -260
  28. data/lib/prawn/grid.rb +219 -57
  29. data/lib/prawn/image_handler.rb +27 -10
  30. data/lib/prawn/images/image.rb +8 -10
  31. data/lib/prawn/images/jpg.rb +46 -20
  32. data/lib/prawn/images/png.rb +94 -42
  33. data/lib/prawn/images.rb +70 -81
  34. data/lib/prawn/measurement_extensions.rb +39 -8
  35. data/lib/prawn/measurements.rb +60 -5
  36. data/lib/prawn/outline.rb +120 -113
  37. data/lib/prawn/repeater.rb +52 -36
  38. data/lib/prawn/security/arcfour.rb +4 -4
  39. data/lib/prawn/security.rb +106 -98
  40. data/lib/prawn/soft_mask.rb +42 -30
  41. data/lib/prawn/stamp.rb +38 -42
  42. data/lib/prawn/text/box.rb +156 -105
  43. data/lib/prawn/text/formatted/arranger.rb +121 -41
  44. data/lib/prawn/text/formatted/box.rb +239 -163
  45. data/lib/prawn/text/formatted/fragment.rb +130 -14
  46. data/lib/prawn/text/formatted/line_wrap.rb +49 -38
  47. data/lib/prawn/text/formatted/parser.rb +116 -74
  48. data/lib/prawn/text/formatted/wrap.rb +25 -26
  49. data/lib/prawn/text/formatted.rb +75 -0
  50. data/lib/prawn/text.rb +456 -211
  51. data/lib/prawn/transformation_stack.rb +29 -10
  52. data/lib/prawn/utilities.rb +13 -13
  53. data/lib/prawn/version.rb +2 -1
  54. data/lib/prawn/view.rb +69 -54
  55. data/lib/prawn.rb +24 -18
  56. data.tar.gz.sig +0 -0
  57. metadata +55 -262
  58. metadata.gz.sig +3 -4
  59. data/.yardopts +0 -10
  60. data/Gemfile +0 -5
  61. data/Rakefile +0 -54
  62. data/manual/absolute_position.pdf +0 -0
  63. data/manual/basic_concepts/adding_pages.rb +0 -26
  64. data/manual/basic_concepts/basic_concepts.rb +0 -43
  65. data/manual/basic_concepts/creation.rb +0 -38
  66. data/manual/basic_concepts/cursor.rb +0 -32
  67. data/manual/basic_concepts/measurement.rb +0 -24
  68. data/manual/basic_concepts/origin.rb +0 -37
  69. data/manual/basic_concepts/other_cursor_helpers.rb +0 -39
  70. data/manual/basic_concepts/view.rb +0 -48
  71. data/manual/bounding_box/bounding_box.rb +0 -41
  72. data/manual/bounding_box/bounds.rb +0 -48
  73. data/manual/bounding_box/canvas.rb +0 -23
  74. data/manual/bounding_box/creation.rb +0 -22
  75. data/manual/bounding_box/indentation.rb +0 -45
  76. data/manual/bounding_box/nesting.rb +0 -52
  77. data/manual/bounding_box/russian_boxes.rb +0 -40
  78. data/manual/bounding_box/stretchy.rb +0 -29
  79. data/manual/contents.rb +0 -35
  80. data/manual/cover.rb +0 -43
  81. data/manual/document_and_page_options/background.rb +0 -25
  82. data/manual/document_and_page_options/document_and_page_options.rb +0 -34
  83. data/manual/document_and_page_options/metadata.rb +0 -25
  84. data/manual/document_and_page_options/page_margins.rb +0 -36
  85. data/manual/document_and_page_options/page_size.rb +0 -34
  86. data/manual/document_and_page_options/print_scaling.rb +0 -22
  87. data/manual/example_helper.rb +0 -8
  88. data/manual/graphics/blend_mode.rb +0 -52
  89. data/manual/graphics/circle_and_ellipse.rb +0 -21
  90. data/manual/graphics/color.rb +0 -22
  91. data/manual/graphics/common_lines.rb +0 -29
  92. data/manual/graphics/fill_and_stroke.rb +0 -41
  93. data/manual/graphics/fill_rules.rb +0 -37
  94. data/manual/graphics/gradients.rb +0 -43
  95. data/manual/graphics/graphics.rb +0 -64
  96. data/manual/graphics/helper.rb +0 -27
  97. data/manual/graphics/line_width.rb +0 -36
  98. data/manual/graphics/lines_and_curves.rb +0 -40
  99. data/manual/graphics/polygon.rb +0 -27
  100. data/manual/graphics/rectangle.rb +0 -20
  101. data/manual/graphics/rotate.rb +0 -25
  102. data/manual/graphics/scale.rb +0 -42
  103. data/manual/graphics/soft_masks.rb +0 -44
  104. data/manual/graphics/stroke_cap.rb +0 -30
  105. data/manual/graphics/stroke_dash.rb +0 -47
  106. data/manual/graphics/stroke_join.rb +0 -29
  107. data/manual/graphics/translate.rb +0 -28
  108. data/manual/graphics/transparency.rb +0 -33
  109. data/manual/how_to_read_this_manual.rb +0 -39
  110. data/manual/images/absolute_position.rb +0 -22
  111. data/manual/images/fit.rb +0 -20
  112. data/manual/images/horizontal.rb +0 -24
  113. data/manual/images/images.rb +0 -41
  114. data/manual/images/plain_image.rb +0 -17
  115. data/manual/images/scale.rb +0 -21
  116. data/manual/images/vertical.rb +0 -27
  117. data/manual/images/width_and_height.rb +0 -24
  118. data/manual/layout/boxes.rb +0 -26
  119. data/manual/layout/content.rb +0 -24
  120. data/manual/layout/layout.rb +0 -27
  121. data/manual/layout/simple_grid.rb +0 -22
  122. data/manual/outline/add_subsection_to.rb +0 -60
  123. data/manual/outline/insert_section_after.rb +0 -46
  124. data/manual/outline/outline.rb +0 -33
  125. data/manual/outline/sections_and_pages.rb +0 -66
  126. data/manual/repeatable_content/alternate_page_numbering.rb +0 -36
  127. data/manual/repeatable_content/page_numbering.rb +0 -55
  128. data/manual/repeatable_content/repeatable_content.rb +0 -35
  129. data/manual/repeatable_content/repeater.rb +0 -54
  130. data/manual/repeatable_content/stamp.rb +0 -40
  131. data/manual/security/encryption.rb +0 -28
  132. data/manual/security/permissions.rb +0 -41
  133. data/manual/security/security.rb +0 -28
  134. data/manual/table.rb +0 -16
  135. data/manual/text/alignment.rb +0 -43
  136. data/manual/text/color.rb +0 -24
  137. data/manual/text/column_box.rb +0 -30
  138. data/manual/text/fallback_fonts.rb +0 -41
  139. data/manual/text/font.rb +0 -40
  140. data/manual/text/font_size.rb +0 -44
  141. data/manual/text/font_style.rb +0 -22
  142. data/manual/text/formatted_callbacks.rb +0 -65
  143. data/manual/text/formatted_text.rb +0 -58
  144. data/manual/text/free_flowing_text.rb +0 -50
  145. data/manual/text/inline.rb +0 -40
  146. data/manual/text/kerning_and_character_spacing.rb +0 -38
  147. data/manual/text/leading.rb +0 -24
  148. data/manual/text/line_wrapping.rb +0 -60
  149. data/manual/text/paragraph_indentation.rb +0 -32
  150. data/manual/text/positioned_text.rb +0 -37
  151. data/manual/text/registering_families.rb +0 -51
  152. data/manual/text/rendering_and_color.rb +0 -36
  153. data/manual/text/right_to_left_text.rb +0 -54
  154. data/manual/text/rotation.rb +0 -47
  155. data/manual/text/single_usage.rb +0 -36
  156. data/manual/text/text.rb +0 -75
  157. data/manual/text/text_box_excess.rb +0 -35
  158. data/manual/text/text_box_extensions.rb +0 -48
  159. data/manual/text/text_box_overflow.rb +0 -49
  160. data/manual/text/utf8.rb +0 -27
  161. data/manual/text/win_ansi_charset.rb +0 -62
  162. data/prawn.gemspec +0 -57
  163. data/spec/data/curves.pdf +0 -66
  164. data/spec/extensions/encoding_helpers.rb +0 -11
  165. data/spec/prawn/document/bounding_box_spec.rb +0 -546
  166. data/spec/prawn/document/column_box_spec.rb +0 -75
  167. data/spec/prawn/document/security_spec.rb +0 -176
  168. data/spec/prawn/document_annotations_spec.rb +0 -76
  169. data/spec/prawn/document_destinations_spec.rb +0 -15
  170. data/spec/prawn/document_grid_spec.rb +0 -99
  171. data/spec/prawn/document_reference_spec.rb +0 -27
  172. data/spec/prawn/document_span_spec.rb +0 -36
  173. data/spec/prawn/document_spec.rb +0 -802
  174. data/spec/prawn/font_metric_cache_spec.rb +0 -54
  175. data/spec/prawn/font_spec.rb +0 -542
  176. data/spec/prawn/graphics/blend_mode_spec.rb +0 -63
  177. data/spec/prawn/graphics/transparency_spec.rb +0 -81
  178. data/spec/prawn/graphics_spec.rb +0 -837
  179. data/spec/prawn/graphics_stroke_styles_spec.rb +0 -229
  180. data/spec/prawn/image_handler_spec.rb +0 -53
  181. data/spec/prawn/images/jpg_spec.rb +0 -20
  182. data/spec/prawn/images/png_spec.rb +0 -283
  183. data/spec/prawn/images_spec.rb +0 -224
  184. data/spec/prawn/measurements_extensions_spec.rb +0 -24
  185. data/spec/prawn/outline_spec.rb +0 -412
  186. data/spec/prawn/repeater_spec.rb +0 -165
  187. data/spec/prawn/soft_mask_spec.rb +0 -74
  188. data/spec/prawn/stamp_spec.rb +0 -172
  189. data/spec/prawn/text/box_spec.rb +0 -1112
  190. data/spec/prawn/text/formatted/arranger_spec.rb +0 -466
  191. data/spec/prawn/text/formatted/box_spec.rb +0 -846
  192. data/spec/prawn/text/formatted/fragment_spec.rb +0 -343
  193. data/spec/prawn/text/formatted/line_wrap_spec.rb +0 -494
  194. data/spec/prawn/text/formatted/parser_spec.rb +0 -697
  195. data/spec/prawn/text_draw_text_spec.rb +0 -149
  196. data/spec/prawn/text_rendering_mode_spec.rb +0 -48
  197. data/spec/prawn/text_spacing_spec.rb +0 -95
  198. data/spec/prawn/text_spec.rb +0 -603
  199. data/spec/prawn/text_with_inline_formatting_spec.rb +0 -35
  200. data/spec/prawn/transformation_stack_spec.rb +0 -66
  201. data/spec/prawn/view_spec.rb +0 -63
  202. data/spec/prawn_manual_spec.rb +0 -35
  203. data/spec/spec_helper.rb +0 -48
data/lib/prawn/font.rb CHANGED
@@ -1,51 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # font.rb : The Prawn font class
4
- #
5
- # Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- #
9
3
  require_relative 'font_metric_cache'
10
4
 
11
5
  module Prawn
12
- class Document
6
+ class Document # rubocop: disable Style/Documentation
13
7
  # @group Stable API
14
8
 
15
- # Without arguments, this returns the currently selected font. Otherwise,
16
- # it sets the current font. When a block is used, the font is applied
9
+ # Default empty options.
10
+ DEFAULT_OPTS = {}.freeze
11
+
12
+ # Without arguments, this returns the currently selected font. Otherwise, it
13
+ # sets the current font. When a block is used, the font is applied
17
14
  # transactionally and is rolled back when the block exits.
18
15
  #
19
- # Prawn::Document.generate("font.pdf") do
20
- # text "Default font is Helvetica"
21
- #
22
- # font "Times-Roman"
23
- # text "Now using Times-Roman"
16
+ # ```ruby
17
+ # Prawn::Document.generate("font.pdf") do
18
+ # text "Default font is Helvetica"
24
19
  #
25
- # font("DejaVuSans.ttf") do
26
- # text "Using TTF font from file DejaVuSans.ttf"
27
- # font "Courier", :style => :bold
28
- # text "You see this in bold Courier"
29
- # end
20
+ # font "Times-Roman"
21
+ # text "Now using Times-Roman"
30
22
  #
31
- # text "Times-Roman, again"
23
+ # font("DejaVuSans.ttf") do
24
+ # text "Using TTF font from file DejaVuSans.ttf"
25
+ # font "Courier", style: :bold
26
+ # text "You see this in bold Courier"
32
27
  # end
33
28
  #
34
- # The :name parameter must be a string. It can be one of the 14 built-in
29
+ # text "Times-Roman, again"
30
+ # end
31
+ # ```
32
+ #
33
+ # The `name` parameter must be a string. It can be one of the 14 built-in
35
34
  # fonts supported by PDF, or the location of a TTF file. The
36
- # Fonts::AFM::BUILT_INS array specifies the valid built in font values.
35
+ # {Fonts::AFM::BUILT_INS} array specifies the valid built in font names.
37
36
  #
38
- # If a ttf font is specified, the glyphs necessary to render your document
39
- # will be embedded in the rendered PDF. This should be your preferred option
40
- # in most cases. It will increase the size of the resulting file, but also
41
- # make it more portable.
37
+ # If a TTF/OTF font is specified, the glyphs necessary to render your
38
+ # document will be embedded in the rendered PDF. This should be your
39
+ # preferred option in most cases. It will increase the size of the resulting
40
+ # file, but also make it more portable.
42
41
  #
43
42
  # The options parameter is an optional hash providing size and style. To use
44
43
  # the :style option you need to map those font styles to their respective
45
44
  # font files.
46
- # See font_families for more information.
47
45
  #
48
- def font(name = nil, options = {})
46
+ # @param name [String] font name. It can be:
47
+ # - One of 14 PDF built-in fonts.
48
+ # - A font file path.
49
+ # - A font name defined in {font_families}
50
+ # @param options [Hash{Symbol => any}]
51
+ # @option options :style [Symbol] font style
52
+ # @yield
53
+ # @return [Font]
54
+ # @see #font_families
55
+ # @see Font::AFM::BUILT_INS
56
+ def font(name = nil, options = DEFAULT_OPTS)
49
57
  return((defined?(@font) && @font) || font('Helvetica')) if name.nil?
50
58
 
51
59
  if state.pages.empty? && !state.page.in_stamp_stream?
@@ -66,32 +74,35 @@ module Prawn
66
74
  @font
67
75
  end
68
76
 
69
- # @method font_size(points=nil)
70
- #
71
77
  # When called with no argument, returns the current font size.
72
78
  #
73
79
  # When called with a single argument but no block, sets the current font
74
- # size. When a block is used, the font size is applied transactionally and
75
- # is rolled back when the block exits. You may still change the font size
80
+ # size. When a block is used, the font size is applied transactionally and
81
+ # is rolled back when the block exits. You may still change the font size
76
82
  # within a transactional block for individual text segments, or nested calls
77
- # to font_size.
83
+ # to `font_size`.
78
84
  #
85
+ # @example
79
86
  # Prawn::Document.generate("font_size.pdf") do
80
87
  # font_size 16
81
88
  # text "At size 16"
82
89
  #
83
90
  # font_size(10) do
84
91
  # text "At size 10"
85
- # text "At size 6", :size => 6
92
+ # text "At size 6", size: 6
86
93
  # text "At size 10"
87
94
  # end
88
95
  #
89
96
  # text "At size 16"
90
97
  # end
91
98
  #
92
- # When called without an argument, this method returns the current font
93
- # size.
94
- #
99
+ # @overload font_size()
100
+ # @return [Number] vurrent font size
101
+ # @overload font_size(points)
102
+ # @param points [Number] new font size
103
+ # @yield if block is provided font size is set only for the duration of
104
+ # the block
105
+ # @return [void]
95
106
  def font_size(points = nil)
96
107
  return @font_size unless points
97
108
 
@@ -101,33 +112,43 @@ module Prawn
101
112
  @font_size = size_before_yield
102
113
  end
103
114
 
104
- # Sets the font size
115
+ # Sets the font size.
116
+ #
117
+ # @param size [Number]
118
+ # @return [Number]
105
119
  def font_size=(size)
106
120
  font_size(size)
107
121
  end
108
122
 
109
- # Returns the width of the given string using the given font. If :size is
123
+ # Returns the width of the given string using the given font. If `:size` is
110
124
  # not specified as one of the options, the string is measured using the
111
- # current font size. You can also pass :kerning as an option to indicate
125
+ # current font size. You can also pass `:kerning` as an option to indicate
112
126
  # whether kerning should be used when measuring the width (defaults to
113
- # +false+).
127
+ # `false`).
114
128
  #
115
129
  # Note that the string _must_ be encoded properly for the font being used.
116
- # For AFM fonts, this is WinAnsi. For TTF, make sure the font is encoded as
117
- # UTF-8. You can use the Font#normalize_encoding method to make sure strings
118
- # are in an encoding appropriate for the current font.
119
- #--
120
- # For the record, this method used to be a method of Font (and still
121
- # delegates to width computations on Font). However, having the primary
122
- # interface for calculating string widths exist on Font made it tricky to
123
- # write extensions for Prawn in which widths are computed differently (e.g.,
124
- # taking formatting tags into account, or the like).
125
- #
126
- # By putting width_of here, on Document itself, extensions may easily
127
- # override it and redefine the width calculation behavior.
128
- #++
130
+ # For AFM fonts, this is WinAnsi. For TTF/OTF, make sure the font is encoded
131
+ # as UTF-8. You can use the Font#normalize_encoding method to make sure
132
+ # strings are in an encoding appropriate for the current font.
133
+ #
134
+ # @devnote
135
+ # For the record, this method used to be a method of Font (and still
136
+ # delegates to width computations on Font). However, having the primary
137
+ # interface for calculating string widths exist on Font made it tricky to
138
+ # write extensions for Prawn in which widths are computed differently
139
+ # (e.g., taking formatting tags into account, or the like).
140
+ #
141
+ # By putting width_of here, on Document itself, extensions may easily
142
+ # override it and redefine the width calculation behavior.
143
+ #
144
+ # @param string [String]
145
+ # @param options [Hash{Symbol => any}]
146
+ # @option options :inline_format [Boolean] (false)
147
+ # @option options :kerning [Boolean] (false)
148
+ # @option options :style [Symbol]
149
+ # @return [Number]
129
150
  def width_of(string, options = {})
130
- if options.key? :inline_format
151
+ if options.key?(:inline_format)
131
152
  p = options[:inline_format]
132
153
  p = [] unless p.is_a?(Array)
133
154
 
@@ -143,69 +164,94 @@ module Prawn
143
164
  end
144
165
  end
145
166
 
146
- # Hash that maps font family names to their styled individual font names.
167
+ # Hash that maps font family names to their styled individual font
168
+ # definitions.
147
169
  #
148
170
  # To add support for another font family, append to this hash, e.g:
149
171
  #
150
- # pdf.font_families.update(
151
- # "MyTrueTypeFamily" => { :bold => "foo-bold.ttf",
152
- # :italic => "foo-italic.ttf",
153
- # :bold_italic => "foo-bold-italic.ttf",
154
- # :normal => "foo.ttf" })
172
+ # ```ruby
173
+ # pdf.font_families.update(
174
+ # "MyTrueTypeFamily" => {
175
+ # bold: "foo-bold.ttf",
176
+ # italic: "foo-italic.ttf",
177
+ # bold_italic: "foo-bold-italic.ttf",
178
+ # normal: "foo.ttf",
179
+ # }
180
+ # )
181
+ # ```
155
182
  #
156
183
  # This will then allow you to use the fonts like so:
157
184
  #
158
- # pdf.font("MyTrueTypeFamily", :style => :bold)
159
- # pdf.text "Some bold text"
160
- # pdf.font("MyTrueTypeFamily")
161
- # pdf.text "Some normal text"
185
+ # ```ruby
186
+ # pdf.font("MyTrueTypeFamily", style: :bold)
187
+ # pdf.text "Some bold text"
188
+ # pdf.font("MyTrueTypeFamily")
189
+ # pdf.text "Some normal text"
190
+ # ```
162
191
  #
163
- # This assumes that you have appropriate TTF fonts for each style you
192
+ # This assumes that you have appropriate TTF/OTF fonts for each style you
164
193
  # wish to support.
165
194
  #
166
- # By default the styles :bold, :italic, :bold_italic, and :normal are
167
- # defined for fonts "Courier", "Times-Roman" and "Helvetica". When
168
- # defining your own font families, you can map any or all of these
169
- # styles to whatever font files you'd like.
195
+ # By default the styles `:bold`, `:italic`, `:bold_italic`, and `:normal`
196
+ # are defined for fonts "Courier", "Times-Roman" and "Helvetica". When
197
+ # defining your own font families, you can map any or all of these styles to
198
+ # whatever font files you'd like.
199
+ #
200
+ # Font definition can be either a hash or just a string.
201
+ #
202
+ # A hash font definition can specify a number of options:
170
203
  #
204
+ # - `:file` -- path to the font file (required)
205
+ # - `:subset` -- whether to subset the font (default false). Only
206
+ # applicable to TrueType and OpenType fonts (includnig DFont and TTC).
207
+ #
208
+ # A string font definition is equivalent to hash definition with only
209
+ # `:file` being specified.
210
+ #
211
+ # @return [Hash{String => Hash{Symbol => String, Hash{Symbol => String}}}]
171
212
  def font_families
172
213
  @font_families ||= {}.merge!(
173
214
  'Courier' => {
174
215
  bold: 'Courier-Bold',
175
216
  italic: 'Courier-Oblique',
176
217
  bold_italic: 'Courier-BoldOblique',
177
- normal: 'Courier'
218
+ normal: 'Courier',
178
219
  },
179
220
 
180
221
  'Times-Roman' => {
181
222
  bold: 'Times-Bold',
182
223
  italic: 'Times-Italic',
183
224
  bold_italic: 'Times-BoldItalic',
184
- normal: 'Times-Roman'
225
+ normal: 'Times-Roman',
185
226
  },
186
227
 
187
228
  'Helvetica' => {
188
229
  bold: 'Helvetica-Bold',
189
230
  italic: 'Helvetica-Oblique',
190
231
  bold_italic: 'Helvetica-BoldOblique',
191
- normal: 'Helvetica'
192
- }
232
+ normal: 'Helvetica',
233
+ },
193
234
  )
194
235
  end
195
236
 
196
237
  # @group Experimental API
197
238
 
198
- # Sets the font directly, given an actual Font object
199
- # and size.
239
+ # Sets the font directly, given an actual {Font} object and size.
200
240
  #
201
- def set_font(font, size = nil) # :nodoc:
241
+ # @private
242
+ # @param font [Font]
243
+ # @param size [Number]
244
+ # @return [void]
245
+ def set_font(font, size = nil)
202
246
  @font = font
203
247
  @font_size = size if size
204
248
  end
205
249
 
206
- # Saves the current font, and then yields. When the block
207
- # finishes, the original font is restored.
250
+ # Saves the current font, and then yields. When the block finishes, the
251
+ # original font is restored.
208
252
  #
253
+ # @yield
254
+ # @return [void]
209
255
  def save_font
210
256
  @font ||= find_font('Helvetica')
211
257
  original_font = @font
@@ -219,22 +265,30 @@ module Prawn
219
265
  # Looks up the given font using the given criteria. Once a font has been
220
266
  # found by that matches the criteria, it will be cached to subsequent
221
267
  # lookups for that font will return the same object.
222
- # --
223
- # Challenges involved: the name alone is not sufficient to uniquely identify
224
- # a font (think dfont suitcases that can hold multiple different fonts in a
225
- # single file). Thus, the :name key is included in the cache key.
226
- #
227
- # It is further complicated, however, since fonts in some formats (like the
228
- # dfont suitcases) can be identified either by numeric index, OR by their
229
- # name within the suitcase, and both should hash to the same font object (to
230
- # avoid the font being embedded multiple times). This is not yet
231
- # implemented, which means if someone selects a font both by name, and by
232
- # index, the font will be embedded twice. Since we do font subsetting, this
233
- # double embedding won't be catastrophic, just annoying.
234
- # ++
268
+ #
269
+ # @devnote
270
+ # Challenges involved: the name alone is not sufficient to uniquely
271
+ # identify a font (think dfont suitcases that can hold multiple different
272
+ # fonts in a single file). Thus, the `:name` key is included in the cache
273
+ # key.
274
+ #
275
+ # It is further complicated, however, since fonts in some formats (like
276
+ # the dfont suitcases) can be identified either by numeric index, OR by
277
+ # their name within the suitcase, and both should hash to the same font
278
+ # object (to avoid the font being embedded multiple times). This is not
279
+ # yet implemented, which means if someone selects a font both by name, and
280
+ # by index, the font will be embedded twice. Since we do font subsetting,
281
+ # this double embedding won't be catastrophic, just annoying.
235
282
  #
236
283
  # @private
237
- def find_font(name, options = {}) #:nodoc:
284
+ # @param name [String]
285
+ # @param options [Hash]
286
+ # @option options :style [Symbol]
287
+ # @option options :file [String]
288
+ # @option options :font [Integer, String] index or name of the font in
289
+ # a font suitcase/collection
290
+ # @return [Font]
291
+ def find_font(name, options = {}) # :nodoc:
238
292
  if font_families.key?(name)
239
293
  family = name
240
294
  name = font_families[name][options[:style] || :normal]
@@ -243,9 +297,9 @@ module Prawn
243
297
  name = options[:file]
244
298
  end
245
299
  end
246
- key = "#{name}:#{options[:font] || 0}"
300
+ key = "#{family}:#{name}:#{options[:font] || 0}"
247
301
 
248
- if name.is_a? Prawn::Font
302
+ if name.is_a?(Prawn::Font)
249
303
  font_registry[key] = name
250
304
  else
251
305
  font_registry[key] ||=
@@ -253,9 +307,11 @@ module Prawn
253
307
  end
254
308
  end
255
309
 
256
- # Hash of Font objects keyed by names
310
+ # Hash of Font objects keyed by names.
257
311
  #
258
- def font_registry #:nodoc:
312
+ # @private
313
+ # @return [Hash{String => Font}]
314
+ def font_registry
259
315
  @font_registry ||= {}
260
316
  end
261
317
 
@@ -278,32 +334,46 @@ module Prawn
278
334
 
279
335
  # Provides font information and helper functions.
280
336
  #
337
+ # @abstract
281
338
  class Font
282
- require_relative 'fonts/afm'
283
- require_relative 'fonts/ttf'
284
- require_relative 'fonts/dfont'
285
- require_relative 'fonts/otf'
286
- require_relative 'fonts/ttc'
339
+ require_relative 'fonts'
340
+
341
+ # @deprecated
342
+ AFM = Prawn::Fonts::AFM
287
343
 
288
344
  # @deprecated
289
- AFM = Fonts::AFM
290
345
  TTF = Fonts::TTF
346
+
347
+ # @deprecated
291
348
  DFont = Fonts::DFont
349
+
350
+ # @deprecated
292
351
  TTC = Fonts::TTC
293
352
 
294
- # The current font name
353
+ # The font name.
354
+ # @return [String]
295
355
  attr_reader :name
296
356
 
297
- # The current font family
357
+ # The font family.
358
+ # @return [String]
298
359
  attr_reader :family
299
360
 
300
- # The options hash used to initialize the font
361
+ # The options hash used to initialize the font.
362
+ # @return [Hash]
301
363
  attr_reader :options
302
364
 
303
- # Shortcut interface for constructing a font object. Filenames of the form
304
- # *.ttf will call Fonts::TTF.new, *.dfont Fonts::DFont.new, *.ttc goes to
305
- # Fonts::TTC.new, and anything else will be passed through to
306
- # Fonts::AFM.new()
365
+ # Shortcut interface for constructing a font object. Filenames of the form
366
+ # `*.ttf` will call {Fonts::TTF#initialize TTF.new}, `*.otf` calls
367
+ # {Fonts::OTF#initialize OTF.new}, `*.dfont` calls {Fonts::DFont#initialize
368
+ # DFont.new}, `*.ttc` goes to {Fonts::TTC#initialize TTC.new}, and anything
369
+ # else will be passed through to {Prawn::Fonts::AFM#initialize AFM.new}.
370
+ #
371
+ # @param document [Prawn::Document] owning document
372
+ # @param src [String] font file path
373
+ # @param options [Hash]
374
+ # @option options :family [String]
375
+ # @option options :style [Symbol]
376
+ # @return [Prawn::Fonts::Font]
307
377
  def self.load(document, src, options = {})
308
378
  case font_format(src, options)
309
379
  when 'ttf' then TTF.new(document, src, options)
@@ -314,19 +384,32 @@ module Prawn
314
384
  end
315
385
  end
316
386
 
387
+ # Guesses font format.
388
+ #
389
+ # @private
390
+ # @param src [String, IO]
391
+ # @param options [Hash]
392
+ # @option options :format [String]
393
+ # @return [String]
317
394
  def self.font_format(src, options)
318
- return options.fetch(:format, 'ttf') if src.respond_to? :read
395
+ return options.fetch(:format, 'ttf') if src.respond_to?(:read)
319
396
 
320
397
  case src.to_s
321
- when /\.ttf$/i then 'ttf'
322
- when /\.otf$/i then 'otf'
398
+ when /\.ttf$/i then 'ttf'
399
+ when /\.otf$/i then 'otf'
323
400
  when /\.dfont$/i then 'dfont'
324
- when /\.ttc$/i then 'ttc'
401
+ when /\.ttc$/i then 'ttc'
325
402
  else 'afm'
326
403
  end
327
404
  end
328
405
 
329
- def initialize(document, name, options = {}) #:nodoc:
406
+ # @private
407
+ # @param document [Prawn::Document]
408
+ # @param name [String]
409
+ # @param options [Hash{Symbol => any}]
410
+ # @option options :family [String]
411
+ # @option options :subset [Boolean] (true)
412
+ def initialize(document, name, options = {})
330
413
  @document = document
331
414
  @name = name
332
415
  @options = options
@@ -336,54 +419,70 @@ module Prawn
336
419
  @identifier = generate_unique_id
337
420
 
338
421
  @references = {}
422
+ @subset_name_cache = {}
423
+
424
+ @full_font_embedding = options.key?(:subset) && !options[:subset]
339
425
  end
340
426
 
341
- # The size of the font ascender in PDF points
427
+ # The size of the font ascender in PDF points.
342
428
  #
429
+ # @return [Number]
343
430
  def ascender
344
431
  @ascender / 1000.0 * size
345
432
  end
346
433
 
347
- # The size of the font descender in PDF points
434
+ # The size of the font descender in PDF points.
348
435
  #
436
+ # @return [Number]
349
437
  def descender
350
438
  -@descender / 1000.0 * size
351
439
  end
352
440
 
353
441
  # The size of the recommended gap between lines of text in PDF points
354
442
  #
443
+ # @return [Number]
355
444
  def line_gap
356
445
  @line_gap / 1000.0 * size
357
446
  end
358
447
 
359
448
  # Normalizes the encoding of the string to an encoding supported by the
360
449
  # font. The string is expected to be UTF-8 going in. It will be re-encoded
361
- # and the new string will be returned. For an in-place (destructive)
362
- # version, see normalize_encoding!.
450
+ # and the new string will be returned.
451
+ #
452
+ # @abstract
453
+ # @!parse def normalize_encoding(string); end
454
+ # @param string [String]
455
+ # @return [String]
363
456
  def normalize_encoding(_string)
364
457
  raise NotImplementedError,
365
458
  'subclasses of Prawn::Font must implement #normalize_encoding'
366
459
  end
367
460
 
368
- # Destructive version of normalize_encoding; normalizes the encoding of a
461
+ # Destructive version of {normalize_encoding}; normalizes the encoding of a
369
462
  # string in place.
370
463
  #
464
+ # @note This method doesn't mutate its argument any more.
465
+ #
371
466
  # @deprecated
467
+ # @param str [String]
468
+ # @return [String]
372
469
  def normalize_encoding!(str)
373
- warn 'Font#normalize_encoding! is deprecated. ' \
374
- 'Please use non-mutating version Font#normalize_encoding instead.'
470
+ warn('Font#normalize_encoding! is deprecated. Please use non-mutating version Font#normalize_encoding instead.')
375
471
  str.dup.replace(normalize_encoding(str))
376
472
  end
377
473
 
378
- # Gets height of current font in PDF points at the given font size
474
+ # Gets height of font in PDF points at the given font size.
379
475
  #
476
+ # @param size [Number]
477
+ # @return [Number]
380
478
  def height_at(size)
381
479
  @normalized_height ||= (@ascender - @descender + @line_gap) / 1000.0
382
480
  @normalized_height * size
383
481
  end
384
482
 
385
- # Gets height of current font in PDF points at current font size
483
+ # Gets height of current font in PDF points at current font size.
386
484
  #
485
+ # @return [Number]
387
486
  def height
388
487
  height_at(size)
389
488
  end
@@ -392,39 +491,53 @@ module Prawn
392
491
  # page. This is safe to call multiple times for a given font and subset,
393
492
  # as it will only add the font the first time it is called.
394
493
  #
494
+ # @param subset [Integer]
495
+ # @return [void]
395
496
  def add_to_current_page(subset)
396
497
  @references[subset] ||= register(subset)
397
- @document.state.page.fonts.merge!(
398
- identifier_for(subset) => @references[subset]
399
- )
498
+ @document.state.page.fonts[identifier_for(subset)] = @references[subset]
400
499
  end
401
500
 
402
- def identifier_for(subset) #:nodoc:
403
- "#{@identifier}.#{subset}".to_sym
501
+ # @private
502
+ # @param subset [Integer]
503
+ # @return [Symbol]
504
+ def identifier_for(subset)
505
+ @subset_name_cache[subset] ||=
506
+ if full_font_embedding
507
+ @identifier.to_sym
508
+ else
509
+ :"#{@identifier}.#{subset}"
510
+ end
404
511
  end
405
512
 
406
- def inspect #:nodoc:
513
+ # Returns a string containing a human-readable representation of this font.
514
+ #
515
+ # @return [String]
516
+ def inspect
407
517
  "#{self.class.name}< #{name}: #{size} >"
408
518
  end
409
519
 
410
- # Return a hash (as in Object#hash) for the font based on the output of
411
- # #inspect. This is required since font objects are used as keys in hashes
412
- # that cache certain values (See
413
- # Prawn::Table::Text#styled_with_of_single_character)
520
+ # Return a hash (as in `Object#hash`) for the font. This is required since
521
+ # font objects are used as keys in hashes that cache certain values.
414
522
  #
415
- def hash #:nodoc:
416
- [self.class, name, family, size].hash
523
+ # @return [Integer]
524
+ def hash
525
+ [self.class, name, family].hash
417
526
  end
418
527
 
419
- # Compliments the #hash implementation above
528
+ # Compliments the {#hash} implementation.
420
529
  #
421
- def eql?(other) #:nodoc:
530
+ # @param other [Object]
531
+ # @return [Boolean]
532
+ def eql?(other)
422
533
  self.class == other.class && name == other.name &&
423
- family == other.family && size == other.send(:size)
534
+ family == other.family && size == other.size
424
535
  end
425
536
 
426
537
  private
427
538
 
539
+ attr_reader :full_font_embedding
540
+
428
541
  # generate a font identifier that hasn't been used on the current page yet
429
542
  #
430
543
  def generate_unique_id
@@ -445,6 +558,8 @@ module Prawn
445
558
  end
446
559
  end
447
560
 
561
+ protected
562
+
448
563
  def size
449
564
  @document.font_size
450
565
  end