prawn-git 2.0.1

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 (252) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -0
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +56 -0
  8. data/Rakefile +55 -0
  9. data/data/fonts/Courier-Bold.afm +342 -0
  10. data/data/fonts/Courier-BoldOblique.afm +342 -0
  11. data/data/fonts/Courier-Oblique.afm +342 -0
  12. data/data/fonts/Courier.afm +342 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/images/16bit.alpha +0 -0
  25. data/data/images/16bit.color +0 -0
  26. data/data/images/16bit.png +0 -0
  27. data/data/images/arrow.png +0 -0
  28. data/data/images/arrow2.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.color +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/dice_interlaced.png +0 -0
  33. data/data/images/fractal.jpg +0 -0
  34. data/data/images/indexed_color.dat +0 -0
  35. data/data/images/indexed_color.png +0 -0
  36. data/data/images/letterhead.jpg +0 -0
  37. data/data/images/license.md +8 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.color +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pal_bk.png +0 -0
  42. data/data/images/pigs.jpg +0 -0
  43. data/data/images/prawn.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/tru256.bmp +0 -0
  50. data/data/images/web-links.dat +1 -0
  51. data/data/images/web-links.png +0 -0
  52. data/data/pdfs/complex_template.pdf +0 -0
  53. data/data/pdfs/contains_ttf_font.pdf +0 -0
  54. data/data/pdfs/encrypted.pdf +0 -0
  55. data/data/pdfs/form.pdf +820 -0
  56. data/data/pdfs/hexagon.pdf +61 -0
  57. data/data/pdfs/indirect_reference.pdf +86 -0
  58. data/data/pdfs/multipage_template.pdf +127 -0
  59. data/data/pdfs/nested_pages.pdf +118 -0
  60. data/data/pdfs/page_without_mediabox.pdf +193 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/lib/prawn.rb +89 -0
  66. data/lib/prawn/document.rb +706 -0
  67. data/lib/prawn/document/bounding_box.rb +539 -0
  68. data/lib/prawn/document/column_box.rb +144 -0
  69. data/lib/prawn/document/internals.rb +58 -0
  70. data/lib/prawn/document/span.rb +57 -0
  71. data/lib/prawn/encoding.rb +87 -0
  72. data/lib/prawn/errors.rb +80 -0
  73. data/lib/prawn/font.rb +413 -0
  74. data/lib/prawn/font/afm.rb +256 -0
  75. data/lib/prawn/font/dfont.rb +43 -0
  76. data/lib/prawn/font/ttf.rb +355 -0
  77. data/lib/prawn/font_metric_cache.rb +46 -0
  78. data/lib/prawn/graphics.rb +646 -0
  79. data/lib/prawn/graphics/cap_style.rb +47 -0
  80. data/lib/prawn/graphics/color.rb +232 -0
  81. data/lib/prawn/graphics/dash.rb +109 -0
  82. data/lib/prawn/graphics/join_style.rb +49 -0
  83. data/lib/prawn/graphics/patterns.rb +126 -0
  84. data/lib/prawn/graphics/transformation.rb +157 -0
  85. data/lib/prawn/graphics/transparency.rb +101 -0
  86. data/lib/prawn/grid.rb +279 -0
  87. data/lib/prawn/image_handler.rb +44 -0
  88. data/lib/prawn/images.rb +199 -0
  89. data/lib/prawn/images/image.rb +49 -0
  90. data/lib/prawn/images/jpg.rb +91 -0
  91. data/lib/prawn/images/png.rb +290 -0
  92. data/lib/prawn/measurement_extensions.rb +50 -0
  93. data/lib/prawn/measurements.rb +77 -0
  94. data/lib/prawn/outline.rb +289 -0
  95. data/lib/prawn/repeater.rb +124 -0
  96. data/lib/prawn/security.rb +288 -0
  97. data/lib/prawn/security/arcfour.rb +54 -0
  98. data/lib/prawn/soft_mask.rb +94 -0
  99. data/lib/prawn/stamp.rb +136 -0
  100. data/lib/prawn/text.rb +437 -0
  101. data/lib/prawn/text/box.rb +141 -0
  102. data/lib/prawn/text/formatted.rb +7 -0
  103. data/lib/prawn/text/formatted/arranger.rb +290 -0
  104. data/lib/prawn/text/formatted/box.rb +614 -0
  105. data/lib/prawn/text/formatted/fragment.rb +264 -0
  106. data/lib/prawn/text/formatted/line_wrap.rb +277 -0
  107. data/lib/prawn/text/formatted/parser.rb +224 -0
  108. data/lib/prawn/text/formatted/wrap.rb +160 -0
  109. data/lib/prawn/utilities.rb +46 -0
  110. data/lib/prawn/version.rb +5 -0
  111. data/lib/prawn/view.rb +91 -0
  112. data/manual/absolute_position.pdf +0 -0
  113. data/manual/basic_concepts/adding_pages.rb +27 -0
  114. data/manual/basic_concepts/basic_concepts.rb +36 -0
  115. data/manual/basic_concepts/creation.rb +39 -0
  116. data/manual/basic_concepts/cursor.rb +33 -0
  117. data/manual/basic_concepts/measurement.rb +25 -0
  118. data/manual/basic_concepts/origin.rb +38 -0
  119. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  120. data/manual/basic_concepts/view.rb +42 -0
  121. data/manual/bounding_box/bounding_box.rb +39 -0
  122. data/manual/bounding_box/bounds.rb +49 -0
  123. data/manual/bounding_box/canvas.rb +24 -0
  124. data/manual/bounding_box/creation.rb +23 -0
  125. data/manual/bounding_box/indentation.rb +46 -0
  126. data/manual/bounding_box/nesting.rb +45 -0
  127. data/manual/bounding_box/russian_boxes.rb +40 -0
  128. data/manual/bounding_box/stretchy.rb +31 -0
  129. data/manual/contents.rb +29 -0
  130. data/manual/cover.rb +39 -0
  131. data/manual/document_and_page_options/background.rb +27 -0
  132. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  133. data/manual/document_and_page_options/metadata.rb +23 -0
  134. data/manual/document_and_page_options/page_margins.rb +38 -0
  135. data/manual/document_and_page_options/page_size.rb +34 -0
  136. data/manual/document_and_page_options/print_scaling.rb +20 -0
  137. data/manual/example_helper.rb +7 -0
  138. data/manual/graphics/circle_and_ellipse.rb +22 -0
  139. data/manual/graphics/color.rb +24 -0
  140. data/manual/graphics/common_lines.rb +30 -0
  141. data/manual/graphics/fill_and_stroke.rb +42 -0
  142. data/manual/graphics/fill_rules.rb +37 -0
  143. data/manual/graphics/gradients.rb +37 -0
  144. data/manual/graphics/graphics.rb +58 -0
  145. data/manual/graphics/helper.rb +24 -0
  146. data/manual/graphics/line_width.rb +35 -0
  147. data/manual/graphics/lines_and_curves.rb +41 -0
  148. data/manual/graphics/polygon.rb +29 -0
  149. data/manual/graphics/rectangle.rb +21 -0
  150. data/manual/graphics/rotate.rb +28 -0
  151. data/manual/graphics/scale.rb +41 -0
  152. data/manual/graphics/soft_masks.rb +46 -0
  153. data/manual/graphics/stroke_cap.rb +31 -0
  154. data/manual/graphics/stroke_dash.rb +48 -0
  155. data/manual/graphics/stroke_join.rb +30 -0
  156. data/manual/graphics/translate.rb +29 -0
  157. data/manual/graphics/transparency.rb +35 -0
  158. data/manual/how_to_read_this_manual.rb +40 -0
  159. data/manual/images/absolute_position.rb +23 -0
  160. data/manual/images/fit.rb +21 -0
  161. data/manual/images/horizontal.rb +25 -0
  162. data/manual/images/images.rb +40 -0
  163. data/manual/images/plain_image.rb +18 -0
  164. data/manual/images/scale.rb +22 -0
  165. data/manual/images/vertical.rb +28 -0
  166. data/manual/images/width_and_height.rb +25 -0
  167. data/manual/layout/boxes.rb +27 -0
  168. data/manual/layout/content.rb +25 -0
  169. data/manual/layout/layout.rb +28 -0
  170. data/manual/layout/simple_grid.rb +23 -0
  171. data/manual/outline/add_subsection_to.rb +61 -0
  172. data/manual/outline/insert_section_after.rb +47 -0
  173. data/manual/outline/outline.rb +32 -0
  174. data/manual/outline/sections_and_pages.rb +67 -0
  175. data/manual/repeatable_content/alternate_page_numbering.rb +32 -0
  176. data/manual/repeatable_content/page_numbering.rb +54 -0
  177. data/manual/repeatable_content/repeatable_content.rb +32 -0
  178. data/manual/repeatable_content/repeater.rb +55 -0
  179. data/manual/repeatable_content/stamp.rb +41 -0
  180. data/manual/security/encryption.rb +31 -0
  181. data/manual/security/permissions.rb +38 -0
  182. data/manual/security/security.rb +28 -0
  183. data/manual/table.rb +16 -0
  184. data/manual/text/alignment.rb +44 -0
  185. data/manual/text/color.rb +24 -0
  186. data/manual/text/column_box.rb +32 -0
  187. data/manual/text/fallback_fonts.rb +37 -0
  188. data/manual/text/font.rb +41 -0
  189. data/manual/text/font_size.rb +45 -0
  190. data/manual/text/font_style.rb +23 -0
  191. data/manual/text/formatted_callbacks.rb +60 -0
  192. data/manual/text/formatted_text.rb +50 -0
  193. data/manual/text/free_flowing_text.rb +51 -0
  194. data/manual/text/inline.rb +41 -0
  195. data/manual/text/kerning_and_character_spacing.rb +39 -0
  196. data/manual/text/leading.rb +25 -0
  197. data/manual/text/line_wrapping.rb +41 -0
  198. data/manual/text/paragraph_indentation.rb +34 -0
  199. data/manual/text/positioned_text.rb +38 -0
  200. data/manual/text/registering_families.rb +48 -0
  201. data/manual/text/rendering_and_color.rb +37 -0
  202. data/manual/text/right_to_left_text.rb +47 -0
  203. data/manual/text/rotation.rb +43 -0
  204. data/manual/text/single_usage.rb +37 -0
  205. data/manual/text/text.rb +73 -0
  206. data/manual/text/text_box_excess.rb +32 -0
  207. data/manual/text/text_box_extensions.rb +45 -0
  208. data/manual/text/text_box_overflow.rb +48 -0
  209. data/manual/text/utf8.rb +28 -0
  210. data/manual/text/win_ansi_charset.rb +60 -0
  211. data/prawn.gemspec +45 -0
  212. data/spec/acceptance/png.rb +25 -0
  213. data/spec/annotations_spec.rb +74 -0
  214. data/spec/bounding_box_spec.rb +510 -0
  215. data/spec/column_box_spec.rb +65 -0
  216. data/spec/data/curves.pdf +66 -0
  217. data/spec/destinations_spec.rb +15 -0
  218. data/spec/document_spec.rb +748 -0
  219. data/spec/extensions/encoding_helpers.rb +11 -0
  220. data/spec/extensions/mocha.rb +46 -0
  221. data/spec/font_metric_cache_spec.rb +52 -0
  222. data/spec/font_spec.rb +474 -0
  223. data/spec/formatted_text_arranger_spec.rb +421 -0
  224. data/spec/formatted_text_box_spec.rb +705 -0
  225. data/spec/formatted_text_fragment_spec.rb +298 -0
  226. data/spec/graphics_spec.rb +683 -0
  227. data/spec/grid_spec.rb +96 -0
  228. data/spec/image_handler_spec.rb +54 -0
  229. data/spec/images_spec.rb +153 -0
  230. data/spec/inline_formatted_text_parser_spec.rb +564 -0
  231. data/spec/jpg_spec.rb +25 -0
  232. data/spec/line_wrap_spec.rb +367 -0
  233. data/spec/measurement_units_spec.rb +25 -0
  234. data/spec/outline_spec.rb +430 -0
  235. data/spec/png_spec.rb +245 -0
  236. data/spec/reference_spec.rb +25 -0
  237. data/spec/repeater_spec.rb +160 -0
  238. data/spec/security_spec.rb +158 -0
  239. data/spec/soft_mask_spec.rb +79 -0
  240. data/spec/span_spec.rb +44 -0
  241. data/spec/spec_helper.rb +54 -0
  242. data/spec/stamp_spec.rb +160 -0
  243. data/spec/stroke_styles_spec.rb +211 -0
  244. data/spec/text_at_spec.rb +143 -0
  245. data/spec/text_box_spec.rb +1043 -0
  246. data/spec/text_rendering_mode_spec.rb +45 -0
  247. data/spec/text_spacing_spec.rb +93 -0
  248. data/spec/text_spec.rb +557 -0
  249. data/spec/text_with_inline_formatting_spec.rb +35 -0
  250. data/spec/transparency_spec.rb +91 -0
  251. data/spec/view_spec.rb +43 -0
  252. metadata +509 -0
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ module EncodingHelpers
4
+ def win1252_string(str)
5
+ str.force_encoding(Encoding::Windows_1252)
6
+ end
7
+
8
+ def bin_string(str)
9
+ str.force_encoding(Encoding::ASCII_8BIT)
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ # Allow speccing things when an expectation matcher runs. Similar to #with, but
4
+ # always succeeds.
5
+ #
6
+ # @pdf.expects(:stroke_line).checking do |from, to|
7
+ # @pdf.map_to_absolute(from).should == [0, 0]
8
+ # end
9
+ #
10
+ # Note that the outer expectation does *not* fail only because the inner one
11
+ # does; in the above example, the outer expectation would only fail if
12
+ # stroke_line were not called.
13
+
14
+ class ParameterChecker < Mocha::ParametersMatcher
15
+ def initialize(&matching_block)
16
+ @expected_parameters = [Mocha::ParameterMatchers::AnyParameters.new]
17
+ @matching_block = matching_block
18
+ end
19
+
20
+ def match?(actual_parameters = [])
21
+ @matching_block.call(*actual_parameters)
22
+
23
+ true # always succeed
24
+ end
25
+ end
26
+
27
+ class Mocha::Expectation
28
+ def checking(&block)
29
+ @parameters_matcher = ParameterChecker.new(&block)
30
+ self
31
+ end
32
+ end
33
+
34
+
35
+ # Equivalent to expects(method_name).at_least(0). More useful when combined
36
+ # with parameter matchers to ignore certain calls for the sake of parameter
37
+ # matching.
38
+ #
39
+ # @pdf.ignores(:stroke_color=).with("000000")
40
+ # @pdf.expects(:stroke_color=).with("ff0000")
41
+ #
42
+ module Mocha::ObjectMethods
43
+ def ignores(method_name)
44
+ expects(method_name).at_least(0)
45
+ end
46
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+ require 'pathname'
5
+
6
+ describe "Font metrics caching" do
7
+ let(:document) { Prawn::Document.new }
8
+
9
+ subject { Prawn::FontMetricCache.new( document ) }
10
+
11
+ it "should start with an empty cache" do
12
+ subject.instance_variable_get( :@cache ).should be_empty
13
+ end
14
+
15
+ it "should cache the width of the provided string" do
16
+ subject.width_of('M', {})
17
+
18
+ subject.instance_variable_get( :@cache ).should have(1).entry
19
+ end
20
+
21
+ it "should only cache a single copy of the same string" do
22
+ subject.width_of('M', {})
23
+ subject.width_of('M', {})
24
+
25
+ subject.instance_variable_get( :@cache ).should have(1).entry
26
+ end
27
+
28
+ it "should cache different copies for different strings" do
29
+ subject.width_of('M', {})
30
+ subject.width_of('W', {})
31
+
32
+ subject.instance_variable_get( :@cache ).should have(2).entries
33
+ end
34
+
35
+ it "should cache different copies of the same string with different font sizes" do
36
+ subject.width_of('M', {})
37
+
38
+ document.font_size 24
39
+ subject.width_of('M', {})
40
+
41
+ subject.instance_variable_get( :@cache ).should have(2).entries
42
+ end
43
+
44
+ it "should cache different copies of the same string with different fonts" do
45
+ subject.width_of('M', {})
46
+
47
+ document.font 'Courier'
48
+ subject.width_of('M', {})
49
+
50
+ subject.instance_variable_get( :@cache ).should have(2).entries
51
+ end
52
+ end
@@ -0,0 +1,474 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+ require 'pathname'
5
+
6
+ describe "Font behavior" do
7
+
8
+ it "should default to Helvetica if no font is specified" do
9
+ @pdf = Prawn::Document.new
10
+ @pdf.font.name.should == "Helvetica"
11
+ end
12
+
13
+ end
14
+
15
+ describe "Font objects" do
16
+
17
+ it "should be equal" do
18
+ font1 = Prawn::Document.new.font
19
+ font2 = Prawn::Document.new.font
20
+
21
+ font1.should eql( font2 )
22
+ end
23
+
24
+ it "should always be the same key" do
25
+ font1 = Prawn::Document.new.font
26
+ font2 = Prawn::Document.new.font
27
+
28
+ hash = Hash.new
29
+
30
+ hash[ font1 ] = "Original"
31
+ hash[ font2 ] = "Overwritten"
32
+
33
+ hash.size.should == 1
34
+
35
+ hash[ font1 ].should == "Overwritten"
36
+ hash[ font2 ].should == "Overwritten"
37
+ end
38
+
39
+ end
40
+
41
+ describe "#width_of" do
42
+ it "should take character spacing into account" do
43
+ create_pdf
44
+ original_width = @pdf.width_of("hello world")
45
+ @pdf.character_spacing(7) do
46
+ @pdf.width_of("hello world").should == original_width + 11 * 7
47
+ end
48
+ end
49
+
50
+ it "should exclude newlines" do
51
+ create_pdf
52
+ # Use a TTF font that has a non-zero width for \n
53
+ @pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
54
+
55
+ @pdf.width_of("\nhello world\n").should ==
56
+ @pdf.width_of("hello world")
57
+ end
58
+
59
+ it "should take formatting into account" do
60
+ create_pdf
61
+
62
+ normal_hello = @pdf.width_of("hello")
63
+ inline_bold_hello = @pdf.width_of("<b>hello</b>", :inline_format => true)
64
+ @pdf.font("Helvetica", :style => :bold) {
65
+ @bold_hello = @pdf.width_of("hello")
66
+ }
67
+
68
+ inline_bold_hello.should be > normal_hello
69
+ inline_bold_hello.should == @bold_hello
70
+ end
71
+
72
+ it "should accept :style as an argument" do
73
+ create_pdf
74
+
75
+ styled_bold_hello = @pdf.width_of("hello", :style => :bold)
76
+ @pdf.font("Helvetica", :style => :bold) {
77
+ @bold_hello = @pdf.width_of("hello")
78
+ }
79
+
80
+ styled_bold_hello.should == @bold_hello
81
+ end
82
+
83
+ it "should calculate styled widths correctly using TTFs" do
84
+ create_pdf
85
+
86
+ @pdf.font_families.update(
87
+ 'DejaVu Sans' => {
88
+ :normal => "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf",
89
+ :bold => "#{Prawn::DATADIR}/fonts/DejaVuSans-Bold.ttf",
90
+ }
91
+ )
92
+ @pdf.font("DejaVu Sans") {
93
+ @styled_bold_hello = @pdf.width_of("hello", :style => :bold)
94
+ }
95
+ @pdf.font("DejaVu Sans", :style => :bold) {
96
+ @bold_hello = @pdf.width_of("hello")
97
+ }
98
+
99
+ @pdf.font("DejaVu Sans") {
100
+ @plain_hello = @pdf.width_of("hello")
101
+ }
102
+
103
+ @plain_hello.should_not == @bold_hello
104
+
105
+ @styled_bold_hello.should == @bold_hello
106
+ end
107
+
108
+ it "should not treat minus as if it were a hyphen", :issue => 578 do
109
+ create_pdf
110
+
111
+ @pdf.width_of("-0.75").should be < @pdf.width_of("25.00")
112
+ end
113
+ end
114
+
115
+ describe "#font_size" do
116
+ it "should allow setting font size in DSL style" do
117
+ create_pdf
118
+ @pdf.font_size 20
119
+ @pdf.font_size.should == 20
120
+ end
121
+ end
122
+
123
+ describe "font style support" do
124
+ before(:each) { create_pdf }
125
+
126
+ it "should complain if there is no @current_page" do
127
+ pdf_without_page = Prawn::Document.new(:skip_page_creation => true)
128
+
129
+ lambda{ pdf_without_page.font "Helvetica" }.
130
+ should raise_error(Prawn::Errors::NotOnPage)
131
+ end
132
+
133
+ it "should allow specifying font style by style name and font family" do
134
+ @pdf.font "Courier", :style => :bold
135
+ @pdf.text "In Courier bold"
136
+
137
+ @pdf.font "Courier", :style => :bold_italic
138
+ @pdf.text "In Courier bold-italic"
139
+
140
+ @pdf.font "Courier", :style => :italic
141
+ @pdf.text "In Courier italic"
142
+
143
+ @pdf.font "Courier", :style => :normal
144
+ @pdf.text "In Normal Courier"
145
+
146
+ @pdf.font "Helvetica"
147
+ @pdf.text "In Normal Helvetica"
148
+
149
+ text = PDF::Inspector::Text.analyze(@pdf.render)
150
+ text.font_settings.map { |e| e[:name] }.should ==
151
+ [:"Courier-Bold", :"Courier-BoldOblique", :"Courier-Oblique",
152
+ :Courier, :Helvetica]
153
+ end
154
+
155
+ it "should allow font familes to be defined in a single dfont" do
156
+ file = "#{Prawn::DATADIR}/fonts/Panic+Sans.dfont"
157
+ @pdf.font_families["Panic Sans"] = {
158
+ :normal => { :file => file, :font => "PanicSans" },
159
+ :italic => { :file => file, :font => "PanicSans-Italic" },
160
+ :bold => { :file => file, :font => "PanicSans-Bold" },
161
+ :bold_italic => { :file => file, :font => "PanicSans-BoldItalic" }
162
+ }
163
+
164
+ @pdf.font "Panic Sans", :style => :italic
165
+ @pdf.text "In PanicSans-Italic"
166
+
167
+ text = PDF::Inspector::Text.analyze(@pdf.render)
168
+ name = text.font_settings.map { |e| e[:name] }.first.to_s
169
+ name = name.sub(/\w+\+/, "subset+")
170
+ name.should == "subset+PanicSans-Italic"
171
+ end
172
+
173
+ it "should accept Pathname objects for font files" do
174
+ file = Pathname.new( "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf" )
175
+ @pdf.font_families["DejaVu Sans"] = {
176
+ :normal => file
177
+ }
178
+
179
+ @pdf.font "DejaVu Sans"
180
+ @pdf.text "In DejaVu Sans"
181
+
182
+ text = PDF::Inspector::Text.analyze(@pdf.render)
183
+ name = text.font_settings.map { |e| e[:name] }.first.to_s
184
+ name = name.sub(/\w+\+/, "subset+")
185
+ name.should == "subset+DejaVuSans"
186
+ end
187
+
188
+ it "should accept IO objects for font files" do
189
+ io = File.open "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
190
+ @pdf.font_families["DejaVu Sans"] = {
191
+ normal: Prawn::Font.load(@pdf, io)
192
+ }
193
+
194
+ @pdf.font "DejaVu Sans"
195
+ @pdf.text "In DejaVu Sans"
196
+
197
+ text = PDF::Inspector::Text.analyze(@pdf.render)
198
+ name = text.font_settings.map { |e| e[:name] }.first.to_s
199
+ name = name.sub(/\w+\+/, "subset+")
200
+ name.should == "subset+DejaVuSans"
201
+ end
202
+ end
203
+
204
+ describe "Transactional font handling" do
205
+ before(:each) { create_pdf }
206
+
207
+ it "should allow setting of size directly when font is created" do
208
+ @pdf.font "Courier", :size => 16
209
+ @pdf.font_size.should == 16
210
+ end
211
+
212
+ it "should allow temporary setting of a new font using a transaction" do
213
+ @pdf.font "Helvetica", :size => 12
214
+
215
+ @pdf.font "Courier", :size => 16 do
216
+ @pdf.font.name.should == "Courier"
217
+ @pdf.font_size.should == 16
218
+ end
219
+
220
+ @pdf.font.name.should == "Helvetica"
221
+ @pdf.font_size.should == 12
222
+ end
223
+
224
+ it "should mask font size when using a transacation" do
225
+ @pdf.font "Courier", :size => 16 do
226
+ @pdf.font_size.should == 16
227
+ end
228
+
229
+ @pdf.font "Times-Roman"
230
+ @pdf.font "Courier"
231
+
232
+ @pdf.font_size.should == 12
233
+ end
234
+
235
+ end
236
+
237
+ describe "Document#page_fonts" do
238
+ before(:each) { create_pdf }
239
+
240
+ it "should register fonts properly by page" do
241
+ @pdf.font "Courier"; @pdf.text("hello")
242
+ @pdf.font "Helvetica"; @pdf.text("hello")
243
+ @pdf.font "Times-Roman"; @pdf.text("hello")
244
+ ["Courier","Helvetica","Times-Roman"].each { |f|
245
+ page_should_include_font(f)
246
+ }
247
+
248
+ @pdf.start_new_page
249
+ @pdf.font "Helvetica"; @pdf.text("hello")
250
+ page_should_include_font("Helvetica")
251
+ page_should_not_include_font("Courier")
252
+ page_should_not_include_font("Times-Roman")
253
+ end
254
+
255
+ def page_includes_font?(font)
256
+ @pdf.page.fonts.values.map { |e| e.data[:BaseFont] }.include?(font.to_sym)
257
+ end
258
+
259
+ def page_should_include_font(font)
260
+ page_includes_font?(font).should be_true
261
+ end
262
+
263
+ def page_should_not_include_font(font)
264
+ page_includes_font?(font).should be_false
265
+ end
266
+
267
+ end
268
+
269
+ describe "AFM fonts" do
270
+
271
+ before do
272
+ create_pdf
273
+ @times = @pdf.find_font "Times-Roman"
274
+ end
275
+
276
+ it "should calculate string width taking into account accented characters" do
277
+ input = win1252_string("\xE9")# é in win-1252
278
+ @times.compute_width_of(input, :size => 12).should == @times.compute_width_of("e", :size => 12)
279
+ end
280
+
281
+ it "should calculate string width taking into account kerning pairs" do
282
+ @times.compute_width_of(win1252_string("To"), :size => 12).should == 13.332
283
+ @times.compute_width_of(win1252_string("To"), :size => 12, :kerning => true).should == 12.372
284
+
285
+ input = win1252_string("T\xF6") # Tö in win-1252
286
+ @times.compute_width_of(input, :size => 12, :kerning => true).should == 12.372
287
+ end
288
+
289
+ it "should encode text without kerning by default" do
290
+ @times.encode_text(win1252_string("To")).should == [[0, "To"]]
291
+ input = win1252_string("T\xE9l\xE9") # Télé in win-1252
292
+ @times.encode_text(input).should == [[0, input]]
293
+ @times.encode_text(win1252_string("Technology")).should == [[0, "Technology"]]
294
+ @times.encode_text(win1252_string("Technology...")).should == [[0, "Technology..."]]
295
+ end
296
+
297
+ it "should encode text with kerning if requested" do
298
+ @times.encode_text(win1252_string("To"), :kerning => true).should == [[0, ["T", 80, "o"]]]
299
+ input = win1252_string("T\xE9l\xE9") # Télé in win-1252
300
+ output = win1252_string("\xE9l\xE9") # élé in win-1252
301
+ @times.encode_text(input, :kerning => true).should == [[0, ["T", 70, output]]]
302
+ @times.encode_text(win1252_string("Technology"), :kerning => true).should == [[0, ["T", 70, "echnology"]]]
303
+ @times.encode_text(win1252_string("Technology..."), :kerning => true).should == [[0, ["T", 70, "echnology", 65, "..."]]]
304
+ end
305
+
306
+ describe "when normalizing encoding" do
307
+
308
+ it "should not modify the original string when normalize_encoding() is used" do
309
+ original = "Foo"
310
+ normalized = @times.normalize_encoding(original)
311
+ original.equal?(normalized).should be_false
312
+ end
313
+
314
+ it "should modify the original string when normalize_encoding!() is used" do
315
+ original = "Foo"
316
+ normalized = @times.normalize_encoding!(original)
317
+ original.equal?(normalized).should be_true
318
+ end
319
+
320
+ end
321
+
322
+ it "should omit /Encoding for symbolic fonts" do
323
+ zapf = @pdf.find_font "ZapfDingbats"
324
+ font_dict = zapf.send(:register, nil)
325
+ font_dict.data[:Encoding].should == nil
326
+ end
327
+
328
+ end
329
+
330
+ describe "#glyph_present" do
331
+ before(:each) { create_pdf }
332
+
333
+ it "should return true when present in an AFM font" do
334
+ font = @pdf.find_font("Helvetica")
335
+ font.glyph_present?("H").should be_true
336
+ end
337
+
338
+ it "should return false when absent in an AFM font" do
339
+ font = @pdf.find_font("Helvetica")
340
+ font.glyph_present?("再").should be_false
341
+ end
342
+
343
+ it "should return true when present in a TTF font" do
344
+ font = @pdf.find_font("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf")
345
+ font.glyph_present?("H").should be_true
346
+ end
347
+
348
+ it "should return false when absent in a TTF font" do
349
+ font = @pdf.find_font("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf")
350
+ font.glyph_present?("再").should be_false
351
+
352
+ font = @pdf.find_font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
353
+ font.glyph_present?("€").should be_false
354
+ end
355
+ end
356
+
357
+ describe "TTF fonts" do
358
+
359
+ before do
360
+ create_pdf
361
+ @font = @pdf.find_font "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
362
+ end
363
+
364
+ it "should calculate string width taking into account accented characters" do
365
+ @font.compute_width_of("é", :size => 12).should == @font.compute_width_of("e", :size => 12)
366
+ end
367
+
368
+ it "should calculate string width taking into account kerning pairs" do
369
+ @font.compute_width_of("To", :size => 12).should be_within(0.01).of(14.65)
370
+ @font.compute_width_of("To", :size => 12, :kerning => true).should be_within(0.01).of(12.61)
371
+ end
372
+
373
+ it "should encode text without kerning by default" do
374
+ @font.encode_text("To").should == [[0, "To"]]
375
+
376
+ tele = "T\216l\216"
377
+ result = @font.encode_text("Télé")
378
+ result.length.should == 1
379
+ result[0][0].should == 0
380
+ result[0][1].bytes.to_a.should == tele.bytes.to_a
381
+
382
+ @font.encode_text("Technology").should == [[0, "Technology"]]
383
+ @font.encode_text("Technology...").should == [[0, "Technology..."]]
384
+ @font.encode_text("Teχnology...").should == [[0, "Te"], [1, "!"], [0, "nology..."]]
385
+ end
386
+
387
+ it "should encode text with kerning if requested" do
388
+ @font.encode_text("To", :kerning => true).should == [[0, ["T", 169.921875, "o"]]]
389
+ @font.encode_text("Technology", :kerning => true).should == [[0, ["T", 169.921875, "echnology"]]]
390
+ @font.encode_text("Technology...", :kerning => true).should == [[0, ["T", 169.921875, "echnology", 142.578125, "..."]]]
391
+ @font.encode_text("Teχnology...", :kerning => true).should == [[0, ["T", 169.921875, "e"]], [1, "!"], [0, ["nology", 142.578125, "..."]]]
392
+ end
393
+
394
+ it "should use the ascender, descender, and cap height from the TTF verbatim" do
395
+ # These metrics are relative to the font's own bbox. They should not be
396
+ # scaled with font size.
397
+ ref = @pdf.ref!({})
398
+ @font.send :embed, ref, 0
399
+
400
+ # Pull out the embedded font descriptor
401
+ descriptor = ref.data[:FontDescriptor].data
402
+ descriptor[:Ascent].should == 759
403
+ descriptor[:Descent].should == -240
404
+ descriptor[:CapHeight].should == 759
405
+ end
406
+
407
+ describe "when normalizing encoding" do
408
+ it "should not modify the original string when normalize_encoding() is used" do
409
+ original = "Foo"
410
+ normalized = @font.normalize_encoding(original)
411
+ original.equal?(normalized).should be_false
412
+ end
413
+
414
+ it "should modify the original string when normalize_encoding!() is used" do
415
+ original = "Foo"
416
+ normalized = @font.normalize_encoding!(original)
417
+ original.equal?(normalized).should be_true
418
+ end
419
+
420
+ end
421
+ end
422
+
423
+ describe "DFont fonts" do
424
+ before do
425
+ create_pdf
426
+ @file = "#{Prawn::DATADIR}/fonts/Panic+Sans.dfont"
427
+ end
428
+
429
+ it "should list all named fonts" do
430
+ list = Prawn::Font::DFont.named_fonts(@file)
431
+ list.sort.should == %w(PanicSans PanicSans-Italic PanicSans-Bold PanicSans-BoldItalic).sort
432
+ end
433
+
434
+ it "should count the number of fonts in the file" do
435
+ Prawn::Font::DFont.font_count(@file).should == 4
436
+ end
437
+
438
+ it "should default selected font to the first one if not specified" do
439
+ font = @pdf.find_font(@file)
440
+ font.basename.should == "PanicSans"
441
+ end
442
+
443
+ it "should allow font to be selected by index" do
444
+ font = @pdf.find_font(@file, :font => 2)
445
+ font.basename.should == "PanicSans-Italic"
446
+ end
447
+
448
+ it "should allow font to be selected by name" do
449
+ font = @pdf.find_font(@file, :font => "PanicSans-BoldItalic")
450
+ font.basename.should == "PanicSans-BoldItalic"
451
+ end
452
+
453
+ it "should cache font object based on selected font" do
454
+ f1 = @pdf.find_font(@file, :font => "PanicSans")
455
+ f2 = @pdf.find_font(@file, :font => "PanicSans-Bold")
456
+ f2.object_id.should_not == f1.object_id
457
+ @pdf.find_font(@file, :font => "PanicSans").object_id.should == f1.object_id
458
+ @pdf.find_font(@file, :font => "PanicSans-Bold").object_id.should == f2.object_id
459
+ end
460
+ end
461
+
462
+ describe "#character_count(text)" do
463
+ it "should work on TTF fonts" do
464
+ create_pdf
465
+ @pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
466
+ @pdf.font.character_count("こんにちは世界").should == 7
467
+ @pdf.font.character_count("Hello, world!").should == 13
468
+ end
469
+
470
+ it "should work on AFM fonts" do
471
+ create_pdf
472
+ @pdf.font.character_count("Hello, world!").should == 13
473
+ end
474
+ end