prawn 0.3.0 → 0.4.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 (87) hide show
  1. data/Rakefile +3 -1
  2. data/data/fonts/Action Man.dfont +0 -0
  3. data/examples/general/measurement_units.rb +2 -2
  4. data/examples/graphics/image_flow.rb +2 -2
  5. data/examples/graphics/stroke_bounds.rb +1 -1
  6. data/examples/m17n/win_ansi_charset.rb +3 -3
  7. data/examples/text/dfont.rb +49 -0
  8. data/examples/text/flowing_text_with_header_and_footer.rb +2 -48
  9. data/examples/text/font_calculations.rb +7 -6
  10. data/examples/text/font_size.rb +4 -4
  11. data/examples/text/text_flow.rb +1 -1
  12. data/lib/prawn.rb +6 -3
  13. data/lib/prawn/compatibility.rb +12 -17
  14. data/lib/prawn/document.rb +10 -10
  15. data/lib/prawn/document/internals.rb +8 -3
  16. data/lib/prawn/document/text.rb +39 -57
  17. data/lib/prawn/document/text/box.rb +1 -2
  18. data/lib/prawn/document/text/wrapping.rb +59 -0
  19. data/lib/prawn/errors.rb +0 -8
  20. data/lib/prawn/font.rb +192 -277
  21. data/lib/prawn/font/afm.rb +199 -0
  22. data/lib/prawn/font/dfont.rb +31 -0
  23. data/lib/prawn/font/ttf.rb +318 -0
  24. data/lib/prawn/graphics.rb +7 -2
  25. data/lib/prawn/images/png.rb +1 -1
  26. data/lib/prawn/reference.rb +7 -4
  27. data/spec/font_spec.rb +154 -61
  28. data/spec/text_spec.rb +47 -6
  29. data/vendor/pdf-inspector/lib/pdf/inspector.rb +1 -1
  30. data/vendor/ttfunk/example.rb +42 -2
  31. data/vendor/ttfunk/lib/ttfunk.rb +96 -42
  32. data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
  33. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
  34. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
  35. data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
  36. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
  37. data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
  38. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
  39. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +46 -0
  40. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
  41. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
  42. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +51 -0
  43. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
  44. data/vendor/ttfunk/lib/ttfunk/table.rb +37 -18
  45. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +24 -84
  46. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
  47. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
  48. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
  49. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
  50. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
  51. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
  52. data/vendor/ttfunk/lib/ttfunk/table/head.rb +38 -19
  53. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +35 -21
  54. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +40 -13
  55. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +69 -38
  56. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
  57. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
  58. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +34 -11
  59. data/vendor/ttfunk/lib/ttfunk/table/name.rb +109 -42
  60. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
  61. data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
  62. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
  63. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
  64. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
  65. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
  66. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
  67. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
  68. metadata +54 -25
  69. data/examples/table/addressbook.csv +0 -6
  70. data/examples/table/cell.rb +0 -40
  71. data/examples/table/currency.csv +0 -1834
  72. data/examples/table/fancy_table.rb +0 -62
  73. data/examples/table/ruport_formatter.rb +0 -53
  74. data/examples/table/table.rb +0 -51
  75. data/examples/table/table_alignment.rb +0 -18
  76. data/examples/table/table_border_color.rb +0 -17
  77. data/examples/table/table_colspan.rb +0 -19
  78. data/examples/table/table_header_color.rb +0 -19
  79. data/examples/table/table_header_underline.rb +0 -15
  80. data/lib/prawn/document/table.rb +0 -338
  81. data/lib/prawn/font/cmap.rb +0 -59
  82. data/lib/prawn/font/metrics.rb +0 -378
  83. data/lib/prawn/font/wrapping.rb +0 -47
  84. data/lib/prawn/graphics/cell.rb +0 -264
  85. data/spec/metrics_spec.rb +0 -62
  86. data/spec/table_spec.rb +0 -179
  87. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +0 -25
@@ -55,8 +55,7 @@ module Prawn
55
55
  private
56
56
 
57
57
  def fit_text_to_box
58
- text = @document.font.metrics.naive_wrap(@text,
59
- @width, @document.font.size)
58
+ text = @document.naive_wrap(@text, @width, @document.font_size)
60
59
 
61
60
  max_lines = (@height / @document.font.height).floor
62
61
 
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ # wrapping.rb : Implementation of naive text wrap
4
+ #
5
+ # Copyright May 2008, Michael Daines. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Document
10
+ module Text
11
+ module Wrapping #:nodoc:
12
+ ruby_18 { $KCODE="U" }
13
+
14
+ # Gets height of text in PDF points at current font size.
15
+ # Text +:line_width+ must be specified in PDF points.
16
+ #
17
+ # If using an AFM, string *must* be encoded as WinAnsi
18
+ # (Use normalize_encoding to convert)
19
+ #
20
+ def height_of(string, line_width, size=font_size)
21
+ string = naive_wrap(string, line_width, size)
22
+ string.lines.to_a.length * font.height_at(size)
23
+ end
24
+
25
+ # TODO: Replace with TeX optimal algorithm
26
+ def naive_wrap(string, line_width, font_size, options = {})
27
+ scan_pattern = options[:mode] == :character ? /./ : /\S+|\s+/
28
+
29
+ output = ""
30
+ string.lines.each do |line|
31
+ accumulated_width = 0
32
+ segments = line.scan(scan_pattern)
33
+
34
+ segments.each do |segment|
35
+ segment_width = font.width_of(segment, :size => font_size, :kerning => options[:kerning])
36
+
37
+ if (accumulated_width + segment_width).round > line_width.round
38
+ output = "#{output.sub(/[ \t]*\n?(\n*)\z/, "\n\\1")}"
39
+
40
+ if segment =~ /\s/
41
+ accumulated_width = 0
42
+ else
43
+ output << segment
44
+ accumulated_width = segment_width
45
+ end
46
+ else
47
+ output << segment
48
+ accumulated_width += segment_width
49
+ end
50
+ end
51
+ end
52
+
53
+ output
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
data/lib/prawn/errors.rb CHANGED
@@ -36,13 +36,5 @@ module Prawn
36
36
  #
37
37
  class UnknownOption < StandardError; end
38
38
 
39
- # This error is raised when table data is malformed
40
- #
41
- class InvalidTableData < StandardError; end
42
-
43
- # This error is raised when an empty or nil table is rendered
44
- #
45
- class EmptyTable < StandardError; end
46
-
47
39
  end
48
40
  end
data/lib/prawn/font.rb CHANGED
@@ -5,358 +5,273 @@
5
5
  # Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
- require "prawn/font/wrapping"
9
- require "prawn/font/metrics"
10
- require "prawn/font/cmap"
8
+ require "prawn/font/afm"
9
+ require "prawn/font/ttf"
10
+ require "prawn/font/dfont"
11
11
 
12
- module Prawn
13
-
14
- class Document
12
+ module Prawn
13
+
14
+ class Document
15
15
  # Without arguments, this returns the currently selected font. Otherwise,
16
16
  # it sets the current font.
17
17
  #
18
18
  # The single parameter must be a string. It can be one of the 14 built-in
19
- # fonts supported by PDF, or the location of a TTF file. The BUILT_INS
19
+ # fonts supported by PDF, or the location of a TTF file. The Font::AFM::BUILT_INS
20
20
  # array specifies the valid built in font values.
21
21
  #
22
22
  # pdf.font "Times-Roman"
23
23
  # pdf.font "Chalkboard.ttf"
24
24
  #
25
- # If a ttf font is specified, the full file will be embedded in the
26
- # rendered PDF. This should be your preferred option in most cases.
27
- # It will increase the size of the resulting file, but also make it
28
- # more portable.
25
+ # If a ttf font is specified, the glyphs necessary to render your document
26
+ # will be embedded in the rendered PDF. This should be your preferred option
27
+ # in most cases. It will increase the size of the resulting file, but also
28
+ # make it more portable.
29
29
  #
30
- def font(name=nil, options={})
30
+ def font(name=nil, options={})
31
31
  return @font || font("Helvetica") if name.nil?
32
32
 
33
+ new_font = find_font(name, options)
34
+
33
35
  if block_given?
34
- original_name = font.name
35
- original_size = font.size
36
- end
37
-
38
- @font = find_font(name, options)
39
- @font.add_to_current_page
40
-
41
- @font.size = options[:size] if options[:size]
42
-
43
- if block_given?
44
- yield
45
- font(original_name, :size => original_size)
36
+ save_font do
37
+ set_font(new_font, options[:size])
38
+ yield
39
+ end
46
40
  else
47
- @font
41
+ set_font(new_font, options[:size])
48
42
  end
43
+
44
+ @font
49
45
  end
50
46
 
51
- # Looks up the given font name. Once a font has been found by that name,
52
- # it will be cached to subsequent lookups for that font will return the
53
- # same object.
47
+ # When called with no argument, returns the current font size.
48
+ # When called with a single argument but no block, sets the current font
49
+ # size. When a block is used, the font size is applied transactionally and
50
+ # is rolled back when the block exits. You may still change the font size
51
+ # within a transactional block for individual text segments, or nested calls
52
+ # to font_size.
53
+ #
54
+ # Prawn::Document.generate("font_size.pdf") do
55
+ # font_size 16
56
+ # text "At size 16"
57
+ #
58
+ # font_size(10) do
59
+ # text "At size 10"
60
+ # text "At size 6", :size => 6
61
+ # text "At size 10"
62
+ # end
63
+ #
64
+ # text "At size 16"
65
+ # end
66
+ #
67
+ # When called without an argument, this method returns the current font
68
+ # size.
69
+ #
70
+ def font_size(points=nil)
71
+ return @font_size unless points
72
+ size_before_yield = @font_size
73
+ @font_size = points
74
+ block_given? ? yield : return
75
+ @font_size = size_before_yield
76
+ end
77
+
78
+ # Sets the font directly, given an actual Font object
79
+ # and size.
80
+ def set_font(font, size=nil) # :nodoc:
81
+ @font = font
82
+ @font_size = size if size
83
+ end
84
+
85
+ # Saves the current font, and then yields. When the block
86
+ # finishes, the original font is restored.
87
+ def save_font
88
+ @font ||= find_font("Helvetica")
89
+ original_font = @font
90
+ original_size = @font_size
91
+
92
+ yield
93
+ ensure
94
+ set_font(original_font, original_size) if original_font
95
+ end
96
+
97
+ # Looks up the given font using the given criteria. Once a font has been
98
+ # found by that matches the criteria, it will be cached to subsequent lookups
99
+ # for that font will return the same object.
100
+ #--
101
+ # Challenges involved: the name alone is not sufficient to uniquely identify
102
+ # a font (think dfont suitcases that can hold multiple different fonts in a
103
+ # single file). Thus, the :name key is included in the cache key.
104
+ #
105
+ # It is further complicated, however, since fonts in some formats (like the
106
+ # dfont suitcases) can be identified either by numeric index, OR by their
107
+ # name within the suitcase, and both should hash to the same font object
108
+ # (to avoid the font being embedded multiple times). This is not yet implemented,
109
+ # which means if someone selects a font both by name, and by index, the
110
+ # font will be embedded twice. Since we do font subsetting, this double
111
+ # embedding won't be catastrophic, just annoying.
112
+ # ++
54
113
  #
55
114
  def find_font(name, options={}) #:nodoc:
56
115
  if font_families.key?(name)
57
116
  family, name = name, font_families[name][options[:style] || :normal]
117
+
118
+ if name.is_a?(Hash)
119
+ options = options.merge(name)
120
+ name = options[:file]
121
+ end
58
122
  end
59
123
 
60
- font_registry[name] ||= Font.new(name, options.merge(:for => self, :family => family))
61
- end
62
-
124
+ key = "#{name}:#{options[:font] || 0}"
125
+ font_registry[key] ||= Font.load(self, name, options.merge(:family => family))
126
+ end
127
+
63
128
  # Hash of Font objects keyed by names
64
129
  #
65
130
  def font_registry #:nodoc:
66
131
  @font_registry ||= {}
67
- end
68
-
132
+ end
133
+
69
134
  # Hash that maps font family names to their styled individual font names
70
- #
135
+ #
71
136
  # To add support for another font family, append to this hash, e.g:
72
137
  #
73
138
  # pdf.font_families.update(
74
- # "MyTrueTypeFamily" => { :bold => "foo-bold.ttf",
139
+ # "MyTrueTypeFamily" => { :bold => "foo-bold.ttf",
75
140
  # :italic => "foo-italic.ttf",
76
141
  # :bold_italic => "foo-bold-italic.ttf",
77
142
  # :normal => "foo.ttf" })
78
143
  #
79
144
  # This will then allow you to use the fonts like so:
80
145
  #
81
- # pdf.font("MyTrueTypeFamily", :style => :bold)
146
+ # pdf.font("MyTrueTypeFamily", :style => :bold)
82
147
  # pdf.text "Some bold text"
83
148
  # pdf.font("MyTrueTypeFamily")
84
149
  # pdf.text "Some normal text"
85
150
  #
86
- # This assumes that you have appropriate TTF fonts for each style you
151
+ # This assumes that you have appropriate TTF fonts for each style you
87
152
  # wish to support.
88
- #
89
- def font_families
90
- @font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
153
+ #
154
+ def font_families
155
+ @font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
91
156
  { "Courier" => { :bold => "Courier-Bold",
92
157
  :italic => "Courier-Oblique",
93
158
  :bold_italic => "Courier-BoldOblique",
94
- :normal => "Courier" },
95
-
159
+ :normal => "Courier" },
160
+
96
161
  "Times-Roman" => { :bold => "Times-Bold",
97
162
  :italic => "Times-Italic",
98
163
  :bold_italic => "Times-BoldItalic",
99
- :normal => "Times-Roman" },
100
-
164
+ :normal => "Times-Roman" },
165
+
101
166
  "Helvetica" => { :bold => "Helvetica-Bold",
102
167
  :italic => "Helvetica-Oblique",
103
168
  :bold_italic => "Helvetica-BoldOblique",
104
- :normal => "Helvetica" }
105
- })
169
+ :normal => "Helvetica" }
170
+ })
106
171
  end
107
172
  end
108
-
109
- # Provides font information and helper functions.
110
- #
173
+
174
+ # Provides font information and helper functions.
175
+ #
111
176
  class Font
112
-
113
- BUILT_INS = %w[ Courier Helvetica Times-Roman Symbol ZapfDingbats
114
- Courier-Bold Courier-Oblique Courier-BoldOblique
115
- Times-Bold Times-Italic Times-BoldItalic
116
- Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique ]
117
-
118
- DEFAULT_SIZE = 12
119
-
120
- # The font metrics object
121
- attr_reader :metrics
122
-
177
+
123
178
  # The current font name
124
179
  attr_reader :name
125
-
180
+
126
181
  # The current font family
127
182
  attr_reader :family
128
-
129
- attr_reader :identifier, :reference #:nodoc:
130
-
131
- # Sets the size of the current font:
132
- #
133
- # font.size = 16
134
- #
135
- attr_writer :size
136
-
137
- def initialize(name,options={}) #:nodoc:
138
- @name = name
139
- @family = options[:family]
140
-
141
- @metrics = Prawn::Font::Metrics[name]
142
- @document = options[:for]
143
-
144
- @document.proc_set :PDF, :Text
145
- @size = DEFAULT_SIZE
146
- @identifier = :"F#{@document.font_registry.size + 1}"
147
-
148
- @reference = nil
149
- end
150
-
151
- def inspect
152
- "Prawn::Font< #{name}: #{size} >"
183
+
184
+ # The options hash used to initialize the font
185
+ attr_reader :options
186
+
187
+ def self.load(document,name,options={})
188
+ case name
189
+ when /\.ttf$/ then TTF.new(document, name, options)
190
+ when /\.dfont$/ then DFont.new(document, name, options)
191
+ when /\.afm$/ then AFM.new(document, name, options)
192
+ else AFM.new(document, name, options)
193
+ end
153
194
  end
154
-
155
- # Sets the default font size for use within a block. Individual overrides
156
- # can be used as desired. The previous font size will be restored after the
157
- # block.
158
- #
159
- # Prawn::Document.generate("font_size.pdf") do
160
- # font.size = 16
161
- # text "At size 16"
162
- #
163
- # font.size(10) do
164
- # text "At size 10"
165
- # text "At size 6", :size => 6
166
- # text "At size 10"
167
- # end
168
- #
169
- # text "At size 16"
170
- # end
171
- #
172
- # When called without an argument, this method returns the current font
173
- # size.
174
- #
175
- def size(points=nil)
176
- return @size unless points
177
- size_before_yield = @size
178
- @size = points
179
- yield
180
- @size = size_before_yield
181
- end
182
-
183
- # Gets width of string in PDF points at current font size
184
- #
185
- # If using an AFM, string *must* be encoded as WinAnsi
186
- # (Use normalize_encoding to convert)
187
- #
188
- def width_of(string)
189
- @metrics.string_width(string,@size)
190
- end
191
-
192
- # Gets height of text in PDF points at current font size.
193
- # Text +:line_width+ must be specified in PDF points.
194
- #
195
- # If using an AFM, string *must* be encoded as WinAnsi
196
- # (Use normalize_encoding to convert)
197
- #
198
- def height_of(text,options={})
199
- @metrics.string_height( text, :font_size => @size,
200
- :line_width => options[:line_width] )
201
- end
202
-
203
- # Gets height of current font in PDF points at current font size
204
- #
205
- def height
206
- @metrics.font_height(@size)
207
- end
208
-
209
- # The height of the ascender at the current font size in PDF points
210
- #
211
- def ascender
212
- @metrics.ascender / 1000.0 * @size
213
- end
214
-
215
- # The height of the descender at the current font size in PDF points
216
- #
217
- def descender
218
- @metrics.descender / 1000.0 * @size
195
+
196
+ def initialize(document,name,options={}) #:nodoc:
197
+ @document = document
198
+ @name = name
199
+ @options = options
200
+
201
+ @family = options[:family]
202
+
203
+ @document.proc_set :PDF, :Text
204
+ @identifier = :"F#{@document.font_registry.size + 1}"
205
+
206
+ @references = {}
219
207
  end
220
-
208
+
209
+ def ascender
210
+ @ascender / 1000.0 * size
211
+ end
212
+
213
+ def descender
214
+ @descender / 1000.0 * size
215
+ end
216
+
221
217
  def line_gap
222
- @metrics.line_gap / 1000.0 * @size
218
+ @line_gap / 1000.0 * size
223
219
  end
224
-
225
- def normalize_encoding(text) # :nodoc:
226
- # check the string is encoded sanely
227
- # - UTF-8 for TTF fonts
228
- # - ISO-8859-1 for Built-In fonts
229
- if @metrics.type0?
230
- normalize_ttf_encoding(text)
231
- else
232
- normalize_builtin_encoding(text)
233
- end
220
+
221
+ def identifier_for(subset)
222
+ "#{@identifier}.#{subset}"
234
223
  end
235
-
236
- def add_to_current_page #:nodoc:
237
- embed! unless @reference
238
- @document.page_fonts.merge!(@identifier => @reference)
239
- end
240
-
241
- private
242
224
 
243
- def embed!
244
- case(name)
245
- when /\.ttf$/i
246
- embed_ttf(name)
247
- else
248
- register_builtin(name)
249
- end
225
+ def inspect
226
+ "#{self.class.name}< #{name}: #{size} >"
250
227
  end
251
228
 
252
- # built-in fonts only work with winansi encoding, so translate the string
253
- def normalize_builtin_encoding(text)
254
- enc = Prawn::Encoding::WinAnsi.new
255
- text.replace text.unpack("U*").collect { |i| enc[i] }.pack("C*")
229
+ # Returns the width of the given string using the given font. If :size is not
230
+ # specified as one of the options, the string is measured using the current
231
+ # font size. You can also pass :kerning as an option to indicate whether
232
+ # kerning should be used when measuring the width (defaults to +false+).
233
+ #
234
+ # Note that the string _must_ be encoded properly for the font being used.
235
+ # For AFM fonts, this is WinAnsi. For TTF, make sure the font is encoded as
236
+ # UTF-8. You can use the #normalize_encoding method to make sure strings
237
+ # are in an encoding appropriate for the font.
238
+ def width_of(string, options={})
239
+ raise NotImplementedError, "subclasses of Prawn::Font must implement #width_of"
256
240
  end
257
241
 
258
- def normalize_ttf_encoding(text)
259
- # TODO: if the current font is a built in one, we can't use the utf-8
260
- # string provided by the user. We should convert it to WinAnsi or
261
- # MacRoman or some such.
262
- if text.respond_to?(:encode!)
263
- # if we're running under a M17n aware VM, ensure the string provided is
264
- # UTF-8 (by converting it if necessary)
265
- begin
266
- text.encode!("UTF-8")
267
- rescue
268
- raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
269
- "#{text.encoding} can not be transparently converted to UTF-8. " +
270
- "Please ensure the encoding of the string you are attempting " +
271
- "to use is set correctly"
272
- end
273
- else
274
- # on a non M17N aware VM, use unpack as a hackish way to verify the
275
- # string is valid utf-8. I thought it was better than loading iconv
276
- # though.
277
- begin
278
- text.unpack("U*")
279
- rescue
280
- raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
281
- "are attempting to render is not encoded in valid UTF-8."
282
- end
283
- end
242
+ # Normalizes the encoding of the string to an encoding supported by the font.
243
+ # The string is expected to be UTF-8 going in, and will be reencoded in-place
244
+ # (the argument will be modified directly). The return value is not defined.
245
+ def normalize_encoding(string)
246
+ raise NotImplementedError, "subclasses of Prawn::Font must implement #normalize_encoding"
284
247
  end
285
-
286
- def register_builtin(name)
287
- unless BUILT_INS.include?(name)
288
- raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
289
- end
290
-
291
- @reference = @document.ref( :Type => :Font,
292
- :Subtype => :Type1,
293
- :BaseFont => name.to_sym,
294
- :Encoding => :WinAnsiEncoding)
295
- end
296
-
297
- def embed_ttf(file)
298
- unless File.file?(file)
299
- raise ArgumentError, "file #{file} does not exist"
300
- end
301
248
 
302
- basename = @metrics.basename
249
+ def height_at(size)
250
+ @normalized_height ||= (@ascender - @descender + @line_gap) / 1000.0
251
+ @normalized_height * size
252
+ end
303
253
 
304
- raise "Can't detect a postscript name for #{file}" if basename.nil?
254
+ # Gets height of current font in PDF points at current font size
255
+ #
256
+ def height
257
+ height_at(size)
258
+ end
305
259
 
306
- @encodings = @metrics.cmap
260
+ # Registers the given subset of the current font with the current PDF
261
+ # page. This is safe to call multiple times for a given font and subset,
262
+ # as it will only add the font the first time it is called.
263
+ #
264
+ def add_to_current_page(subset)
265
+ @references[subset] ||= register(subset)
266
+ @document.page_fonts.merge!(identifier_for(subset) => @references[subset])
267
+ end
307
268
 
308
- if @encodings.nil?
309
- raise "#{file} missing the required encoding table"
310
- end
269
+ private
311
270
 
312
- font_content = File.open(file,"rb") { |f| f.read }
313
- compressed_font = Zlib::Deflate.deflate(font_content)
314
-
315
- fontfile = @document.ref(:Length => compressed_font.size,
316
- :Length1 => font_content.size,
317
- :Filter => :FlateDecode )
318
- fontfile << compressed_font
319
-
320
- # TODO: Not sure what to do about CapHeight, as ttf2afm doesn't
321
- # pick it up. Missing proper StemV and flags
322
- #
323
- descriptor = @document.ref(:Type => :FontDescriptor,
324
- :FontName => basename,
325
- :FontFile2 => fontfile,
326
- :FontBBox => @metrics.bbox,
327
- :Flags => 32, # FIXME: additional flags
328
- :StemV => 0,
329
- :ItalicAngle => 0,
330
- :Ascent => @metrics.ascender,
331
- :Descent => @metrics.descender )
332
-
333
- descendant = @document.ref(:Type => :Font,
334
- :Subtype => :CIDFontType2, # CID, TTF
335
- :BaseFont => basename,
336
- :CIDSystemInfo => { :Registry => "Adobe",
337
- :Ordering => "Identity",
338
- :Supplement => 0 },
339
- :FontDescriptor => descriptor,
340
- :W => @metrics.glyph_widths,
341
- :CIDToGIDMap => :Identity )
342
-
343
- to_unicode_content = @metrics.to_unicode_cmap.to_s
344
- compressed_to_unicode = Zlib::Deflate.deflate(to_unicode_content)
345
-
346
- to_unicode = @document.ref(:Length => compressed_to_unicode.size,
347
- :Length1 => to_unicode_content.size,
348
- :Filter => :FlateDecode )
349
- to_unicode << compressed_to_unicode
350
-
351
- @reference = @document.ref(:Type => :Font,
352
- :Subtype => :Type0,
353
- :BaseFont => basename,
354
- :DescendantFonts => [descendant],
355
- :Encoding => :"Identity-H",
356
- :ToUnicode => to_unicode)
357
-
358
- end
271
+ def size
272
+ @document.font_size
273
+ end
359
274
 
360
275
  end
361
-
276
+
362
277
  end