prawn 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +6 -10
  2. data/Rakefile +4 -13
  3. data/data/encodings/win_ansi.txt +29 -0
  4. data/data/images/fractal.jpg +0 -0
  5. data/data/images/letterhead.jpg +0 -0
  6. data/examples/bounding_box/bounding_boxes.rb +44 -0
  7. data/examples/bounding_box/lazy_bounding_boxes.rb +28 -0
  8. data/examples/bounding_box/padded_box.rb +24 -0
  9. data/examples/{russian_boxes.rb → bounding_box/russian_boxes.rb} +9 -6
  10. data/examples/general/background.rb +20 -0
  11. data/examples/{canvas.rb → general/canvas.rb} +6 -2
  12. data/examples/general/measurement_units.rb +52 -0
  13. data/examples/{multi_page_layout.rb → general/multi_page_layout.rb} +6 -3
  14. data/examples/{page_geometry.rb → general/page_geometry.rb} +6 -2
  15. data/examples/{image.rb → graphics/basic_images.rb} +8 -4
  16. data/examples/graphics/cmyk.rb +13 -0
  17. data/examples/graphics/curves.rb +12 -0
  18. data/examples/{hexagon.rb → graphics/hexagon.rb} +5 -5
  19. data/examples/graphics/image_fit.rb +16 -0
  20. data/examples/graphics/image_flow.rb +38 -0
  21. data/examples/graphics/image_position.rb +18 -0
  22. data/examples/{line.rb → graphics/line.rb} +4 -2
  23. data/examples/{png_types.rb → graphics/png_types.rb} +4 -4
  24. data/examples/{polygons.rb → graphics/polygons.rb} +5 -4
  25. data/examples/graphics/remote_images.rb +12 -0
  26. data/examples/{ruport_helpers.rb → graphics/ruport_style_helpers.rb} +8 -5
  27. data/examples/graphics/stroke_bounds.rb +23 -0
  28. data/examples/{chinese_text_wrapping.rb → m17n/chinese_text_wrapping.rb} +7 -4
  29. data/examples/m17n/euro.rb +16 -0
  30. data/examples/m17n/sjis.rb +29 -0
  31. data/examples/m17n/utf8.rb +14 -0
  32. data/examples/m17n/win_ansi_charset.rb +55 -0
  33. data/examples/{addressbook.csv → table/addressbook.csv} +0 -0
  34. data/examples/{cell.rb → table/cell.rb} +8 -6
  35. data/examples/{currency.csv → table/currency.csv} +0 -0
  36. data/examples/{fancy_table.rb → table/fancy_table.rb} +9 -6
  37. data/examples/{ruport_formatter.rb → table/ruport_formatter.rb} +6 -3
  38. data/examples/{table.rb → table/table.rb} +6 -2
  39. data/examples/table/table_alignment.rb +18 -0
  40. data/examples/table/table_border_color.rb +17 -0
  41. data/examples/table/table_colspan.rb +19 -0
  42. data/examples/table/table_header_color.rb +19 -0
  43. data/examples/table/table_header_underline.rb +15 -0
  44. data/examples/{alignment.rb → text/alignment.rb} +5 -2
  45. data/examples/text/family_based_styling.rb +25 -0
  46. data/examples/{flowing_text_with_header_and_footer.rb → text/flowing_text_with_header_and_footer.rb} +19 -8
  47. data/examples/text/font_calculations.rb +91 -0
  48. data/examples/text/font_size.rb +34 -0
  49. data/examples/{kerning.rb → text/kerning.rb} +5 -1
  50. data/examples/text/simple_text.rb +18 -0
  51. data/examples/text/simple_text_ttf.rb +18 -0
  52. data/examples/{span.rb → text/span.rb} +5 -2
  53. data/examples/text/text_box.rb +26 -0
  54. data/examples/{text_flow.rb → text/text_flow.rb} +5 -2
  55. data/lib/prawn.rb +26 -20
  56. data/lib/prawn/compatibility.rb +5 -8
  57. data/lib/prawn/document.rb +29 -13
  58. data/lib/prawn/document/annotations.rb +63 -0
  59. data/lib/prawn/document/bounding_box.rb +18 -3
  60. data/lib/prawn/document/destinations.rb +81 -0
  61. data/lib/prawn/document/internals.rb +16 -2
  62. data/lib/prawn/document/page_geometry.rb +58 -57
  63. data/lib/prawn/document/span.rb +8 -0
  64. data/lib/prawn/document/table.rb +81 -31
  65. data/lib/prawn/document/text.rb +66 -21
  66. data/lib/prawn/document/text/box.rb +77 -0
  67. data/lib/prawn/encoding.rb +121 -0
  68. data/lib/prawn/errors.rb +4 -0
  69. data/lib/prawn/font.rb +70 -42
  70. data/lib/prawn/font/metrics.rb +64 -119
  71. data/lib/prawn/graphics.rb +105 -87
  72. data/lib/prawn/graphics/cell.rb +55 -28
  73. data/lib/prawn/graphics/color.rb +8 -0
  74. data/lib/prawn/images.rb +55 -12
  75. data/lib/prawn/images/jpg.rb +2 -1
  76. data/lib/prawn/images/png.rb +2 -1
  77. data/lib/prawn/literal_string.rb +14 -0
  78. data/lib/prawn/measurement_extensions.rb +46 -0
  79. data/lib/prawn/measurements.rb +71 -0
  80. data/lib/prawn/name_tree.rb +165 -0
  81. data/lib/prawn/pdf_object.rb +8 -1
  82. data/spec/annotations_spec.rb +90 -0
  83. data/spec/destinations_spec.rb +15 -0
  84. data/spec/document_spec.rb +39 -2
  85. data/spec/font_spec.rb +22 -0
  86. data/spec/graphics_spec.rb +99 -87
  87. data/spec/images_spec.rb +29 -1
  88. data/spec/measurement_units_spec.rb +23 -0
  89. data/spec/metrics_spec.rb +3 -2
  90. data/spec/name_tree_spec.rb +103 -0
  91. data/spec/pdf_object_spec.rb +15 -5
  92. data/spec/png_spec.rb +14 -14
  93. data/spec/spec_helper.rb +8 -6
  94. data/spec/table_spec.rb +40 -0
  95. data/spec/text_spec.rb +6 -4
  96. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  97. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  98. data/vendor/ttfunk/example.rb +5 -0
  99. data/vendor/ttfunk/lib/ttfunk.rb +48 -0
  100. data/vendor/ttfunk/lib/ttfunk/table.rb +27 -0
  101. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +94 -0
  102. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +25 -0
  103. data/vendor/ttfunk/lib/ttfunk/table/head.rb +25 -0
  104. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +27 -0
  105. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +20 -0
  106. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +48 -0
  107. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +17 -0
  108. data/vendor/ttfunk/lib/ttfunk/table/name.rb +52 -0
  109. metadata +93 -62
  110. data/examples/bounding_boxes.rb +0 -30
  111. data/examples/curves.rb +0 -10
  112. data/examples/family_based_styling.rb +0 -21
  113. data/examples/font_size.rb +0 -19
  114. data/examples/image2.rb +0 -13
  115. data/examples/image_flow.rb +0 -29
  116. data/examples/lazy_bounding_boxes.rb +0 -19
  117. data/examples/remote_images.rb +0 -7
  118. data/examples/simple_text.rb +0 -15
  119. data/examples/simple_text_ttf.rb +0 -16
  120. data/examples/sjis.rb +0 -21
  121. data/examples/utf8.rb +0 -12
  122. data/vendor/font_ttf/ttf.rb +0 -20
  123. data/vendor/font_ttf/ttf/datatypes.rb +0 -189
  124. data/vendor/font_ttf/ttf/encodings.rb +0 -140
  125. data/vendor/font_ttf/ttf/exceptions.rb +0 -28
  126. data/vendor/font_ttf/ttf/file.rb +0 -290
  127. data/vendor/font_ttf/ttf/fontchunk.rb +0 -77
  128. data/vendor/font_ttf/ttf/table/cmap.rb +0 -408
  129. data/vendor/font_ttf/ttf/table/cvt.rb +0 -49
  130. data/vendor/font_ttf/ttf/table/fpgm.rb +0 -48
  131. data/vendor/font_ttf/ttf/table/gasp.rb +0 -88
  132. data/vendor/font_ttf/ttf/table/glyf.rb +0 -452
  133. data/vendor/font_ttf/ttf/table/head.rb +0 -86
  134. data/vendor/font_ttf/ttf/table/hhea.rb +0 -96
  135. data/vendor/font_ttf/ttf/table/hmtx.rb +0 -98
  136. data/vendor/font_ttf/ttf/table/kern.rb +0 -186
  137. data/vendor/font_ttf/ttf/table/loca.rb +0 -75
  138. data/vendor/font_ttf/ttf/table/maxp.rb +0 -81
  139. data/vendor/font_ttf/ttf/table/name.rb +0 -222
  140. data/vendor/font_ttf/ttf/table/os2.rb +0 -172
  141. data/vendor/font_ttf/ttf/table/post.rb +0 -120
  142. data/vendor/font_ttf/ttf/table/prep.rb +0 -27
  143. data/vendor/font_ttf/ttf/table/vhea.rb +0 -45
  144. data/vendor/font_ttf/ttf/table/vmtx.rb +0 -36
@@ -6,10 +6,12 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
  require "zlib"
9
+ require "prawn/document/text/box"
9
10
 
10
11
  module Prawn
11
12
  class Document
12
13
  module Text
14
+
13
15
  # Draws text on the page. If a point is specified via the +:at+
14
16
  # option the text will begin exactly at that point, and the string is
15
17
  # assumed to be pre-formatted to properly fit the page.
@@ -37,15 +39,45 @@ module Prawn
37
39
  # text will be kerned by default. You can disable this feature by passing
38
40
  # <tt>:kerning => false</tt>.
39
41
  #
40
- # === Character Encoding Details:
42
+ # === Text Positioning Details:
43
+ #
44
+ # When using the :at parameter, Prawn will position your text by its
45
+ # baseline, and flow along a single line.
46
+ #
47
+ # When using automatic text flow, Prawn currently does a bunch of nasty
48
+ # hacks to get things to position nicely in bounding boxes, table cells,
49
+ # etc.
50
+ #
51
+ # For AFM fonts, the first line of text is positioned font.height below
52
+ # the baseline.
53
+ #
54
+ # For TTF fonts, the first line is possitioned font.ascender below the
55
+ # baseline.
56
+ #
57
+ # The issue here is that there are complex issues with determining the
58
+ # size of the glyphs above and below the baseline in TTF that we haven't
59
+ # figured out yet, and that AFM and TTF appear to handle things very
60
+ # differently.
61
+ #
62
+ # The moral of the story is that if you want reliable font positioning
63
+ # for your advanced needs, use :at, otherwise, just let Prawn do its
64
+ # positioning magic for you, or investigate and help us get rid of this
65
+ # ugly issue.
66
+ #
67
+ # == Rotation
68
+ #
69
+ # Text can be rotated before it is placed on the canvas by specifying the
70
+ # :rotate option. Rotation occurs counter-clockwise.
71
+ #
72
+ # == Encoding
41
73
  #
42
74
  # Note that strings passed to this function should be encoded as UTF-8.
43
75
  # If you get unexpected characters appearing in your rendered document,
44
76
  # check this.
45
77
  #
46
78
  # If the current font is a built-in one, although the string must be
47
- # encoded as UTF-8, only characters that are available in ISO-8859-1
48
- # are allowed (transliteration will be attempted).
79
+ # encoded as UTF-8, only characters that are available in WinAnsi
80
+ # are allowed.
49
81
  #
50
82
  # If an empty box is rendered to your PDF instead of the character you
51
83
  # wanted it usually means the current font doesn't include that character.
@@ -67,6 +99,9 @@ module Prawn
67
99
  x,y = translate(options[:at])
68
100
  font.size(options[:size]) { add_text_content(text,x,y,options) }
69
101
  else
102
+ if options[:rotate]
103
+ raise ArgumentError, "Rotated text may only be used with :at"
104
+ end
70
105
  wrapped_text(text,options)
71
106
  end
72
107
 
@@ -86,7 +121,7 @@ module Prawn
86
121
 
87
122
  def process_text_options(options)
88
123
  Prawn.verify_options [:style, :kerning, :size, :at, :wrap,
89
- :spacing, :align ], options
124
+ :spacing, :align, :rotate ], options
90
125
 
91
126
  if options[:style]
92
127
  raise "Bad font family" unless font.family
@@ -115,10 +150,14 @@ module Prawn
115
150
  text = font.metrics.naive_wrap(text, bounds.right, font.size,
116
151
  :kerning => options[:kerning], :mode => options[:wrap])
117
152
 
118
- lines = text.lines
153
+ lines = text.lines.to_a
119
154
 
120
- lines.each do |e|
121
- move_text_position( font.height + font.descender )
155
+ lines.each_with_index do |e,i|
156
+ if font.metrics.type0?
157
+ move_text_position(font.ascender)
158
+ else
159
+ move_text_position(font.height)
160
+ end
122
161
 
123
162
  line_width = font.width_of(e)
124
163
  case(options[:align])
@@ -132,27 +171,33 @@ module Prawn
132
171
  end
133
172
 
134
173
  add_text_content(e,x,y,options)
135
- move_text_position(options[:spacing] || -font.descender )
174
+
175
+ if font.metrics.type0? && i < lines.length - 1
176
+ move_text_position(font.height - font.ascender)
177
+ end
178
+
179
+ move_text_position(options[:spacing]) if options[:spacing]
136
180
  end
137
181
  end
138
182
  end
139
-
183
+
140
184
  def add_text_content(text, x, y, options)
141
185
  text = font.metrics.convert_text(text,options)
142
186
 
143
- add_content %Q{
144
- BT
145
- /#{font.identifier} #{font.size} Tf
146
- #{x} #{y} Td
147
- }
148
-
187
+ add_content "\nBT"
188
+ add_content "/#{font.identifier} #{font.size} Tf"
189
+ if options[:rotate]
190
+ rad = options[:rotate].to_i * Math::PI / 180
191
+ arr = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ]
192
+ add_content "%.3f %.3f %.3f %.3f %.3f %.3f Tm" % arr
193
+ else
194
+ add_content "#{x} #{y} Td"
195
+ end
196
+ rad = 1.570796
149
197
  add_content Prawn::PdfObject(text, true) <<
150
- " #{options[:kerning] ? 'TJ' : 'Tj'}\n"
151
-
152
- add_content %Q{
153
- ET
154
- }
155
- end
198
+ " #{options[:kerning] ? 'TJ' : 'Tj'}"
199
+ add_content "ET\n"
200
+ end
156
201
  end
157
202
  end
158
203
  end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ # text/box.rb : Implements simple text boxes
4
+ #
5
+ # Copyright September 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+
12
+ # Defines an invisible rectangle which you can flow text in. When the
13
+ # text overflows the box, you can either display :ellipses, :truncate
14
+ # the text, or allow it to :overflow the bottom boundary.
15
+ #
16
+ # text_box "Oh hai text box. " * 200,
17
+ # :width => 300, :height => font.height * 5,
18
+ # :overflow => :ellipses,
19
+ # :at => [100,bounds.top]
20
+ #
21
+ def text_box(text,options)
22
+ Text::Box.new(text, options.merge(:for => self)).render
23
+ end
24
+
25
+ module Text
26
+ class Box #:nodoc:
27
+ def initialize(text,options={})
28
+ @document = options[:for]
29
+ @text = text
30
+ @at = options[:at] || [0, @document.y - @document.bounds.absolute_bottom]
31
+ @width = options[:width] || @document.bounds.width
32
+ @height = options[:height]
33
+ @overflow = options[:overflow] || :truncate
34
+ end
35
+
36
+ def render
37
+ x,y = @at
38
+
39
+ unless @overflow == :expand
40
+ original_y = @document.y
41
+ fit_text_to_box
42
+ end
43
+
44
+ @document.bounding_box([x,@document.bounds.top],
45
+ :width => @width, :height => @document.bounds.height) do
46
+ @document.y = @document.bounds.absolute_bottom + y
47
+ @document.text @text
48
+ end
49
+
50
+ unless @overflow == :expand
51
+ @document.y = y + @document.bounds.absolute_bottom - @height
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def fit_text_to_box
58
+ text = @document.font.metrics.naive_wrap(@text,
59
+ @width, @document.font.size)
60
+
61
+ max_lines = (@height / @document.font.height).floor
62
+
63
+ lines = text.lines.to_a
64
+
65
+ unless lines.length < max_lines
66
+ @text = lines[0...max_lines].join
67
+ case(@overflow)
68
+ when :ellipses
69
+ @text[-3..-1] = "..."
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright September 2008, Gregory Brown, James Healy All Rights Reserved.
4
+ #
5
+ # This is free software. Please see the LICENSE and COPYING files for details.
6
+ #
7
+ module Prawn
8
+ module Encoding
9
+ # Map between unicode and WinAnsiEnoding
10
+ #
11
+ class WinAnsi #:nodoc:
12
+ CHARACTERS = %w[
13
+ .notdef .notdef .notdef .notdef
14
+ .notdef .notdef .notdef .notdef
15
+ .notdef .notdef .notdef .notdef
16
+ .notdef .notdef .notdef .notdef
17
+ .notdef .notdef .notdef .notdef
18
+ .notdef .notdef .notdef .notdef
19
+ .notdef .notdef .notdef .notdef
20
+ .notdef .notdef .notdef .notdef
21
+
22
+ space exclam quotedbl numbersign
23
+ dollar percent ampersand quotesingle
24
+ parenleft parenright asterisk plus
25
+ comma hyphen period slash
26
+ zero one two three
27
+ four five six seven
28
+ eight nine colon semicolon
29
+ less equal greater question
30
+
31
+ at A B C
32
+ D E F G
33
+ H I J K
34
+ L M N O
35
+ P Q R S
36
+ T U V W
37
+ X Y Z bracketleft
38
+ backslash bracketright asciicircum underscore
39
+
40
+ grave a b c
41
+ d e f g
42
+ h i j k
43
+ l m n o
44
+ p q r s
45
+ t u v w
46
+ x y z braceleft
47
+ bar braceright asciitilde .notdef
48
+
49
+ Euro .notdef quotesinglbase florin
50
+ quotedblbase ellipsis dagger daggerdbl
51
+ circumflex perthousand Scaron guilsinglleft
52
+ OE .notdef Zcaron .notdef
53
+ .notdef quoteleft quoteright quotedblleft
54
+ quotedblright bullet endash emdash
55
+ tilde trademark scaron guilsinglright
56
+ oe .notdef zcaron ydieresis
57
+
58
+ space exclamdown cent sterling
59
+ currency yen brokenbar section
60
+ dieresis copyright ordfeminine guillemotleft
61
+ logicalnot hyphen registered macron
62
+ degree plusminus twosuperior threesuperior
63
+ acute mu paragraph periodcentered
64
+ cedilla onesuperior ordmasculine guillemotright
65
+ onequarter onehalf threequarters questiondown
66
+
67
+ Agrave Aacute Acircumflex Atilde
68
+ Adieresis Aring AE Ccedilla
69
+ Egrave Eacute Ecircumflex Edieresis
70
+ Igrave Iacute Icircumflex Idieresis
71
+ Eth Ntilde Ograve Oacute
72
+ Ocircumflex Otilde Odieresis multiply
73
+ Oslash Ugrave Uacute Ucircumflex
74
+ Udieresis Yacute Thorn germandbls
75
+
76
+ agrave aacute acircumflex atilde
77
+ adieresis aring ae ccedilla
78
+ egrave eacute ecircumflex edieresis
79
+ igrave iacute icircumflex idieresis
80
+ eth ntilde ograve oacute
81
+ ocircumflex otilde odieresis divide
82
+ oslash ugrave uacute ucircumflex
83
+ udieresis yacute thorn ydieresis
84
+ ]
85
+
86
+ def initialize
87
+ @mapping_file = "#{Prawn::BASEDIR}/data/encodings/win_ansi.txt"
88
+ load_mapping if self.class.mapping.empty?
89
+ end
90
+
91
+ # Converts a Unicode codepoint into a valid WinAnsi single byte character.
92
+ #
93
+ # If there is no WinAnsi equivlant for a character, a _ will be substituted.
94
+ #
95
+ def [](codepoint)
96
+ # unicode codepoints < 255 map directly to the single byte value in WinAnsi
97
+ return codepoint if codepoint <= 255
98
+
99
+ # There are a handful of codepoints > 255 that have equivilants in WinAnsi.
100
+ # Replace anything else with an underscore
101
+ self.class.mapping[codepoint] || 95
102
+ end
103
+
104
+ def self.mapping
105
+ @mapping ||= {}
106
+ end
107
+
108
+ private
109
+
110
+ def load_mapping
111
+ RUBY_VERSION >= "1.9" ? mode = "r:BINARY" : mode = "r"
112
+ File.open(@mapping_file, mode) do |f|
113
+ f.each do |l|
114
+ m, single_byte, unicode = *l.match(/([0-9A-Za-z]+);([0-9A-F]{4})/)
115
+ self.class.mapping["0x#{unicode}".hex] = "0x#{single_byte}".hex if single_byte
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -39,6 +39,10 @@ module Prawn
39
39
  # This error is raised when table data is malformed
40
40
  #
41
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
42
46
 
43
47
  end
44
48
  end
@@ -1,5 +1,10 @@
1
1
  # encoding: utf-8
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.
3
8
  require "prawn/font/wrapping"
4
9
  require "prawn/font/metrics"
5
10
  require "prawn/font/cmap"
@@ -7,7 +12,8 @@ require "prawn/font/cmap"
7
12
  module Prawn
8
13
 
9
14
  class Document
10
- # Sets the current font.
15
+ # Without arguments, this returns the currently selected font. Otherwise,
16
+ # it sets the current font.
11
17
  #
12
18
  # The single parameter must be a string. It can be one of the 14 built-in
13
19
  # fonts supported by PDF, or the location of a TTF file. The BUILT_INS
@@ -22,19 +28,36 @@ module Prawn
22
28
  # more portable.
23
29
  #
24
30
  def font(name=nil, options={})
25
- if name
26
- if font_families.key?(name)
27
- ff = name
28
- name = font_families[name][options[:style] || :normal]
29
- end
30
- Prawn::Font.register(name,:for => self, :family => ff) unless font_registry[name]
31
- font_registry[name].add_to_current_page
32
- @font_name = name
33
- elsif @font_name.nil?
34
- Prawn::Font.register("Helvetica", :for => self, :family => "Helvetica")
35
- @font_name = "Helvetica"
36
- end
37
- font_registry[@font_name]
31
+ return @font || font("Helvetica") if name.nil?
32
+
33
+ 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)
46
+ else
47
+ @font
48
+ end
49
+ end
50
+
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.
54
+ #
55
+ def find_font(name, options={}) #:nodoc:
56
+ if font_families.key?(name)
57
+ family, name = name, font_families[name][options[:style] || :normal]
58
+ end
59
+
60
+ font_registry[name] ||= Font.new(name, options.merge(:for => self, :family => family))
38
61
  end
39
62
 
40
63
  # Hash of Font objects keyed by names
@@ -94,10 +117,6 @@ module Prawn
94
117
 
95
118
  DEFAULT_SIZE = 12
96
119
 
97
- def self.register(name,options={}) #:nodoc:
98
- options[:for].font_registry[name] = Font.new(name,options)
99
- end
100
-
101
120
  # The font metrics object
102
121
  attr_reader :metrics
103
122
 
@@ -125,16 +144,13 @@ module Prawn
125
144
  @document.proc_set :PDF, :Text
126
145
  @size = DEFAULT_SIZE
127
146
  @identifier = :"F#{@document.font_registry.size + 1}"
128
-
129
- case(name)
130
- when /\.ttf$/i
131
- embed_ttf(name)
132
- else
133
- register_builtin(name)
134
- end
135
-
136
- add_to_current_page
137
- end
147
+
148
+ @reference = nil
149
+ end
150
+
151
+ def inspect
152
+ "Prawn::Font< #{name}: #{size} >"
153
+ end
138
154
 
139
155
  # Sets the default font size for use within a block. Individual overrides
140
156
  # can be used as desired. The previous font size will be restored after the
@@ -166,6 +182,9 @@ module Prawn
166
182
 
167
183
  # Gets width of string in PDF points at current font size
168
184
  #
185
+ # If using an AFM, string *must* be encoded as WinAnsi
186
+ # (Use normalize_encoding to convert)
187
+ #
169
188
  def width_of(string)
170
189
  @metrics.string_width(string,@size)
171
190
  end
@@ -173,6 +192,9 @@ module Prawn
173
192
  # Gets height of text in PDF points at current font size.
174
193
  # Text +:line_width+ must be specified in PDF points.
175
194
  #
195
+ # If using an AFM, string *must* be encoded as WinAnsi
196
+ # (Use normalize_encoding to convert)
197
+ #
176
198
  def height_of(text,options={})
177
199
  @metrics.string_height( text, :font_size => @size,
178
200
  :line_width => options[:line_width] )
@@ -195,6 +217,10 @@ module Prawn
195
217
  def descender
196
218
  @metrics.descender / 1000.0 * @size
197
219
  end
220
+
221
+ def line_gap
222
+ @metrics.line_gap / 1000.0 * @size
223
+ end
198
224
 
199
225
  def normalize_encoding(text) # :nodoc:
200
226
  # check the string is encoded sanely
@@ -208,23 +234,25 @@ module Prawn
208
234
  end
209
235
 
210
236
  def add_to_current_page #:nodoc:
237
+ embed! unless @reference
211
238
  @document.page_fonts.merge!(@identifier => @reference)
212
239
  end
213
240
 
214
241
  private
215
-
216
- # built-in fonts only work with latin encoding, so translate the string
217
- def normalize_builtin_encoding(text)
218
- if text.respond_to?(:encode!)
219
- text.encode!("ISO-8859-1")
242
+
243
+ def embed!
244
+ case(name)
245
+ when /\.ttf$/i
246
+ embed_ttf(name)
220
247
  else
221
- require 'iconv'
222
- text.replace Iconv.conv('ISO-8859-1//TRANSLIT', 'utf-8', text)
223
- end
224
- rescue
225
- raise Prawn::Errors::IncompatibleStringEncoding, "When using a " +
226
- "builtin font, only characters that exist in " +
227
- "WinAnsi/ISO-8859-1 are allowed."
248
+ register_builtin(name)
249
+ end
250
+ end
251
+
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*")
228
256
  end
229
257
 
230
258
  def normalize_ttf_encoding(text)
@@ -275,7 +303,7 @@ module Prawn
275
303
 
276
304
  raise "Can't detect a postscript name for #{file}" if basename.nil?
277
305
 
278
- @encodings = @metrics.enc_table
306
+ @encodings = @metrics.cmap
279
307
 
280
308
  if @encodings.nil?
281
309
  raise "#{file} missing the required encoding table"