prawn 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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"