prawn 0.11.1.pre → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. data/COPYING +2 -340
  2. data/HACKING +1 -1
  3. data/LICENSE +3 -3
  4. data/Rakefile +17 -6
  5. data/data/encodings/win_ansi.txt +1 -1
  6. data/data/images/prawn.png +0 -0
  7. data/data/pdfs/form.pdf +820 -0
  8. data/data/pdfs/multipage_template.pdf +127 -0
  9. data/examples/bounding_box/bounding_boxes.rb +4 -3
  10. data/examples/bounding_box/indentation.rb +2 -1
  11. data/examples/bounding_box/russian_boxes.rb +3 -2
  12. data/examples/bounding_box/stretched_nesting.rb +2 -1
  13. data/examples/general/background.rb +2 -1
  14. data/examples/general/canvas.rb +2 -1
  15. data/examples/general/context_sensitive_headers.rb +2 -1
  16. data/examples/general/float.rb +2 -1
  17. data/examples/general/margin.rb +2 -1
  18. data/examples/general/measurement_units.rb +2 -1
  19. data/examples/general/metadata-info.rb +2 -1
  20. data/examples/general/multi_page_layout.rb +2 -1
  21. data/examples/general/outlines.rb +2 -1
  22. data/examples/general/page_geometry.rb +2 -1
  23. data/examples/general/page_numbering.rb +27 -2
  24. data/examples/general/page_templates.rb +20 -0
  25. data/examples/general/repeaters.rb +2 -1
  26. data/examples/general/stamp.rb +4 -3
  27. data/examples/general/templates.rb +2 -1
  28. data/examples/graphics/basic_images.rb +2 -1
  29. data/examples/graphics/cmyk.rb +2 -1
  30. data/examples/graphics/curves.rb +4 -3
  31. data/examples/graphics/gradient.rb +23 -0
  32. data/examples/graphics/hexagon.rb +3 -2
  33. data/examples/graphics/image_fit.rb +3 -2
  34. data/examples/graphics/image_flow.rb +2 -1
  35. data/examples/graphics/image_position.rb +3 -2
  36. data/examples/graphics/line.rb +2 -1
  37. data/examples/graphics/png_types.rb +3 -2
  38. data/examples/graphics/polygons.rb +3 -2
  39. data/examples/graphics/remote_images.rb +2 -1
  40. data/examples/graphics/rounded_polygons.rb +2 -1
  41. data/examples/graphics/rounded_rectangle.rb +2 -1
  42. data/examples/graphics/ruport_style_helpers.rb +3 -2
  43. data/examples/graphics/stroke_bounds.rb +2 -1
  44. data/examples/graphics/stroke_cap_and_join.rb +2 -1
  45. data/examples/graphics/stroke_dash.rb +2 -1
  46. data/examples/graphics/transformations.rb +2 -1
  47. data/examples/graphics/transparency.rb +4 -3
  48. data/examples/grid/bounding_boxes.rb +2 -1
  49. data/examples/grid/column_gutter_grid.rb +2 -1
  50. data/examples/grid/multi_boxes.rb +2 -1
  51. data/examples/grid/show_grid.rb +2 -1
  52. data/examples/grid/simple_grid.rb +2 -1
  53. data/examples/m17n/chinese_text_wrapping.rb +2 -1
  54. data/examples/m17n/euro.rb +3 -2
  55. data/examples/m17n/full_win_ansi_character_list.rb +20 -0
  56. data/examples/m17n/sjis.rb +2 -1
  57. data/examples/m17n/utf8.rb +3 -2
  58. data/examples/m17n/win_ansi_charset.rb +2 -1
  59. data/examples/security/hello_foo.rb +2 -1
  60. data/examples/table/bill.rb +2 -1
  61. data/examples/table/borders.rb +25 -0
  62. data/examples/table/cell.rb +3 -2
  63. data/examples/table/checkerboard.rb +2 -1
  64. data/examples/table/header.rb +3 -2
  65. data/examples/table/inline_format_table.rb +2 -1
  66. data/examples/table/multi_page_table.rb +2 -1
  67. data/examples/table/simple_table.rb +2 -1
  68. data/examples/table/subtable.rb +2 -1
  69. data/examples/table/widths.rb +2 -1
  70. data/examples/text/alignment.rb +2 -1
  71. data/examples/text/character_spacing.rb +2 -1
  72. data/examples/text/dfont.rb +2 -1
  73. data/examples/text/family_based_styling.rb +3 -2
  74. data/examples/text/font_calculations.rb +2 -1
  75. data/examples/text/font_size.rb +2 -1
  76. data/examples/text/hyphenation.rb +2 -2
  77. data/examples/text/indent_paragraphs.rb +7 -5
  78. data/examples/text/inline_format.rb +7 -6
  79. data/examples/text/kerning.rb +2 -1
  80. data/examples/text/rendering_mode.rb +21 -0
  81. data/examples/text/rotated.rb +2 -1
  82. data/examples/text/shaped_text_box.rb +2 -1
  83. data/examples/text/simple_text.rb +2 -1
  84. data/examples/text/simple_text_ttf.rb +2 -1
  85. data/examples/text/span.rb +3 -2
  86. data/examples/text/text_box.rb +7 -5
  87. data/examples/text/text_box_returning_excess.rb +4 -3
  88. data/examples/text/text_flow.rb +2 -1
  89. data/lib/prawn.rb +1 -1
  90. data/lib/prawn/core/object_store.rb +42 -14
  91. data/lib/prawn/core/page.rb +22 -8
  92. data/lib/prawn/core/text.rb +141 -13
  93. data/lib/prawn/core/text/formatted/arranger.rb +39 -12
  94. data/lib/prawn/core/text/formatted/line_wrap.rb +205 -60
  95. data/lib/prawn/core/text/formatted/wrap.rb +72 -35
  96. data/lib/prawn/document.rb +174 -70
  97. data/lib/prawn/document/bounding_box.rb +122 -83
  98. data/lib/prawn/document/column_box.rb +113 -0
  99. data/lib/prawn/document/graphics_state.rb +90 -2
  100. data/lib/prawn/document/internals.rb +5 -3
  101. data/lib/prawn/errors.rb +5 -0
  102. data/lib/prawn/font.rb +4 -4
  103. data/lib/prawn/font/afm.rb +11 -0
  104. data/lib/prawn/font/ttf.rb +5 -0
  105. data/lib/prawn/graphics.rb +77 -14
  106. data/lib/prawn/graphics/cap_style.rb +13 -5
  107. data/lib/prawn/graphics/color.rb +54 -35
  108. data/lib/prawn/graphics/dash.rb +27 -16
  109. data/lib/prawn/graphics/gradient.rb +84 -0
  110. data/lib/prawn/graphics/join_style.rb +12 -3
  111. data/lib/prawn/graphics/transparency.rb +4 -4
  112. data/lib/prawn/images.rb +18 -160
  113. data/lib/prawn/images/jpg.rb +39 -0
  114. data/lib/prawn/images/png.rb +130 -0
  115. data/lib/prawn/repeater.rb +6 -13
  116. data/lib/prawn/security.rb +6 -1
  117. data/lib/prawn/stamp.rb +12 -4
  118. data/lib/prawn/table.rb +36 -4
  119. data/lib/prawn/table/cell.rb +224 -63
  120. data/lib/prawn/table/cell/text.rb +20 -10
  121. data/lib/prawn/table/cells.rb +23 -6
  122. data/lib/prawn/text.rb +54 -91
  123. data/lib/prawn/text/box.rb +29 -283
  124. data/lib/prawn/text/formatted/box.rb +349 -24
  125. data/lib/prawn/text/formatted/fragment.rb +63 -2
  126. data/lib/prawn/text/formatted/parser.rb +2 -1
  127. data/prawn.gemspec +21 -5
  128. data/spec/bounding_box_spec.rb +61 -28
  129. data/spec/cell_spec.rb +168 -30
  130. data/spec/document_spec.rb +187 -3
  131. data/spec/extensions/mocha.rb +45 -0
  132. data/spec/font_spec.rb +32 -1
  133. data/spec/formatted_text_arranger_spec.rb +35 -40
  134. data/spec/formatted_text_box_spec.rb +287 -443
  135. data/spec/formatted_text_fragment_spec.rb +87 -0
  136. data/spec/graphics_spec.rb +128 -12
  137. data/spec/grid_spec.rb +1 -1
  138. data/spec/images_spec.rb +11 -3
  139. data/spec/inline_formatted_text_parser_spec.rb +8 -0
  140. data/spec/line_wrap_spec.rb +200 -208
  141. data/spec/object_store_spec.rb +10 -0
  142. data/spec/outline_spec.rb +7 -3
  143. data/spec/repeater_spec.rb +58 -10
  144. data/spec/security_spec.rb +6 -0
  145. data/spec/spec_helper.rb +12 -8
  146. data/spec/stamp_spec.rb +52 -1
  147. data/spec/stroke_styles_spec.rb +30 -0
  148. data/spec/table_spec.rb +93 -3
  149. data/spec/template_spec.rb +132 -6
  150. data/spec/text_at_spec.rb +14 -4
  151. data/spec/text_box_spec.rb +309 -70
  152. data/spec/text_rendering_mode_spec.rb +45 -0
  153. data/spec/text_spec.rb +60 -17
  154. data/spec/text_with_inline_formatting_spec.rb +4 -162
  155. metadata +241 -241
  156. data/lib/prawn/core/text/line_wrap.rb +0 -211
  157. data/lib/prawn/core/text/wrap.rb +0 -82
  158. data/vendor/pdf-inspector/README +0 -18
  159. data/vendor/pdf-inspector/lib/pdf/inspector.rb +0 -26
  160. data/vendor/pdf-inspector/lib/pdf/inspector/extgstate.rb +0 -18
  161. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +0 -131
  162. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +0 -25
  163. data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +0 -46
  164. data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +0 -19
  165. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  166. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  167. data/vendor/ttfunk/example.rb +0 -45
  168. data/vendor/ttfunk/lib/ttfunk.rb +0 -102
  169. data/vendor/ttfunk/lib/ttfunk/directory.rb +0 -17
  170. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +0 -88
  171. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +0 -69
  172. data/vendor/ttfunk/lib/ttfunk/reader.rb +0 -44
  173. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +0 -78
  174. data/vendor/ttfunk/lib/ttfunk/subset.rb +0 -18
  175. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +0 -141
  176. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +0 -50
  177. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +0 -48
  178. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +0 -63
  179. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +0 -55
  180. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +0 -72
  181. data/vendor/ttfunk/lib/ttfunk/table.rb +0 -46
  182. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +0 -34
  183. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +0 -54
  184. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +0 -126
  185. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +0 -79
  186. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +0 -64
  187. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +0 -81
  188. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +0 -37
  189. data/vendor/ttfunk/lib/ttfunk/table/head.rb +0 -44
  190. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +0 -41
  191. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +0 -47
  192. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +0 -79
  193. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +0 -62
  194. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +0 -43
  195. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +0 -40
  196. data/vendor/ttfunk/lib/ttfunk/table/name.rb +0 -125
  197. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +0 -78
  198. data/vendor/ttfunk/lib/ttfunk/table/post.rb +0 -91
  199. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +0 -43
  200. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +0 -35
  201. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +0 -23
  202. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +0 -17
  203. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +0 -17
  204. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +0 -14
@@ -48,7 +48,7 @@ describe "Document built from a template" do
48
48
 
49
49
  @pdf = Prawn::Document.new(:template => filename)
50
50
  output = StringIO.new(@pdf.render)
51
- hash = PDF::Hash.new(output)
51
+ hash = PDF::Reader::ObjectHash.new(output)
52
52
 
53
53
  hash.each_value do |obj|
54
54
  next unless obj.kind_of?(PDF::Reader::Stream)
@@ -63,7 +63,7 @@ describe "Document built from a template" do
63
63
 
64
64
  @pdf = Prawn::Document.new(:template => filename)
65
65
  output = StringIO.new(@pdf.render)
66
- hash = PDF::Hash.new(output)
66
+ hash = PDF::Reader::ObjectHash.new(output)
67
67
 
68
68
  pages = hash.values.select { |obj| obj.kind_of?(Hash) && obj[:Type] == :Page }
69
69
 
@@ -75,7 +75,7 @@ describe "Document built from a template" do
75
75
 
76
76
  @pdf = Prawn::Document.new(:template => filename)
77
77
  output = StringIO.new(@pdf.render)
78
- hash = PDF::Hash.new(output)
78
+ hash = PDF::Reader::ObjectHash.new(output)
79
79
 
80
80
  streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
81
81
 
@@ -96,7 +96,7 @@ describe "Document built from a template" do
96
96
 
97
97
  @pdf = Prawn::Document.new(:template => filename)
98
98
  output = StringIO.new(@pdf.render)
99
- hash = PDF::Hash.new(output)
99
+ hash = PDF::Reader::ObjectHash.new(output)
100
100
 
101
101
  streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
102
102
 
@@ -126,7 +126,7 @@ describe "Document built from a template" do
126
126
  @pdf.text "Adding some text"
127
127
 
128
128
  text = PDF::Inspector::Text.analyze(@pdf.render)
129
- all_text = text.strings.join("")
129
+ all_text = text.strings.join
130
130
  all_text.include?("Adding some text").should == true
131
131
  end
132
132
 
@@ -146,7 +146,7 @@ describe "Document built from a template" do
146
146
  @pdf.text "Hi There"
147
147
 
148
148
  output = StringIO.new(@pdf.render)
149
- hash = PDF::Hash.new(output)
149
+ hash = PDF::Reader::ObjectHash.new(output)
150
150
 
151
151
  page_dict = hash.values.detect{ |obj| obj.is_a?(Hash) && obj[:Type] == :Page }
152
152
  resources = page_dict[:Resources]
@@ -163,3 +163,129 @@ describe "Document built from a template" do
163
163
  end
164
164
 
165
165
  end
166
+
167
+ describe "Document#start_new_page with :template option" do
168
+ filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
169
+
170
+ it "should set start the Y cursor at the top of the page" do
171
+ @pdf = Prawn::Document.new()
172
+ @pdf.start_new_page(:template => filename)
173
+ (@pdf.y == nil).should == false
174
+ end
175
+
176
+ it "should respect margins set by Prawn" do
177
+ @pdf = Prawn::Document.new(:margin => 0)
178
+ @pdf.start_new_page(:template => filename)
179
+ assert_equal @pdf.page.margins, { :left => 0,
180
+ :right => 0,
181
+ :top => 0,
182
+ :bottom => 0 }
183
+
184
+ @pdf = Prawn::Document.new(:left_margin => 0)
185
+ @pdf.start_new_page(:template => filename)
186
+ assert_equal @pdf.page.margins, { :left => 0,
187
+ :right => 36,
188
+ :top => 36,
189
+ :bottom => 36 }
190
+ @pdf.start_new_page(:template => filename, :right_margin => 0)
191
+ assert_equal @pdf.page.margins, { :left => 0,
192
+ :right => 0,
193
+ :top => 36,
194
+ :bottom => 36 }
195
+ end
196
+
197
+ it "should not add an extra restore_graphics_state operator to the end of any content stream" do
198
+ @pdf = Prawn::Document.new
199
+ @pdf.start_new_page(:template => filename)
200
+ output = StringIO.new(@pdf.render)
201
+ hash = PDF::Reader::ObjectHash.new(output)
202
+
203
+ hash.each_value do |obj|
204
+ next unless obj.kind_of?(PDF::Reader::Stream)
205
+
206
+ data = obj.data.tr(" \n\r","")
207
+ data.include?("QQ").should == false
208
+ end
209
+ end
210
+
211
+ it "should have two content streams if importing a single page template" do
212
+ filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
213
+ @pdf = Prawn::Document.new()
214
+ @pdf.start_new_page(:template => filename)
215
+ output = StringIO.new(@pdf.render)
216
+ hash = PDF::Reader::ObjectHash.new(output)
217
+ pages = hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
218
+ template_page = hash[pages[1]]
219
+ template_page[:Contents].size.should == 2
220
+ end
221
+
222
+ it "should have balance q/Q operators on all content streams" do
223
+ filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
224
+
225
+ @pdf = Prawn::Document.new()
226
+ @pdf.start_new_page(:template => filename)
227
+ output = StringIO.new(@pdf.render)
228
+ hash = PDF::Reader::ObjectHash.new(output)
229
+
230
+ streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
231
+
232
+ streams.each do |stream|
233
+ data = stream.unfiltered_data
234
+ data.scan("q").size.should == 1
235
+ data.scan("Q").size.should == 1
236
+ end
237
+ end
238
+
239
+ it "should allow text to be added to a single page template" do
240
+
241
+ @pdf = Prawn::Document.new()
242
+ @pdf.start_new_page(:template => filename)
243
+
244
+ @pdf.text "Adding some text"
245
+
246
+ text = PDF::Inspector::Text.analyze(@pdf.render)
247
+ text.strings.first.should == "Adding some text"
248
+ end
249
+
250
+ it "should allow PDFs with page resources behind an indirect object to be used as templates" do
251
+ filename = "#{Prawn::BASEDIR}/data/pdfs/resources_as_indirect_object.pdf"
252
+
253
+ @pdf = Prawn::Document.new()
254
+ @pdf.start_new_page(:template => filename)
255
+
256
+ @pdf.text "Adding some text"
257
+
258
+ text = PDF::Inspector::Text.analyze(@pdf.render)
259
+ all_text = text.strings.join
260
+ all_text.include?("Adding some text").should == true
261
+ end
262
+
263
+ it "should correctly add a TTF font to a template that has existing fonts" do
264
+ filename = "#{Prawn::BASEDIR}/data/pdfs/contains_ttf_font.pdf"
265
+ @pdf = Prawn::Document.new()
266
+ @pdf.start_new_page(:template => filename)
267
+ @pdf.font "#{Prawn::BASEDIR}/data/fonts/Chalkboard.ttf"
268
+ @pdf.move_down(40)
269
+ @pdf.text "Hi There"
270
+
271
+ output = StringIO.new(@pdf.render)
272
+ hash = PDF::Reader::ObjectHash.new(output)
273
+ hash = PDF::Reader::ObjectHash.new(output)
274
+ pages = hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
275
+ template_page = hash[pages[1]]
276
+ resources = template_page[:Resources]
277
+ fonts = resources[:Font]
278
+ fonts.size.should == 2
279
+ end
280
+
281
+ context "using template_page option" do
282
+ it "uses the specified page option" do
283
+ filename = "#{Prawn::BASEDIR}/data/pdfs/multipage_template.pdf"
284
+ @pdf = Prawn::Document.new()
285
+ @pdf.start_new_page(:template => filename, :template_page => 2)
286
+ text = PDF::Inspector::Text.analyze(@pdf.render)
287
+ text.strings.first.should == "This is template page 2"
288
+ end
289
+ end
290
+
291
+ end
data/spec/text_at_spec.rb CHANGED
@@ -13,6 +13,12 @@ describe "#draw_text" do
13
13
  lambda { @pdf.draw_text("hai", :at => [0, 0], :align => :center) }.should.raise(ArgumentError)
14
14
  end
15
15
 
16
+ it "should allow drawing empty strings to the page" do
17
+ @pdf.draw_text(" ", :at => [100,100])
18
+ text = PDF::Inspector::Text.analyze(@pdf.render)
19
+ text.strings.first.should == " "
20
+ end
21
+
16
22
  it "should default to 12 point helvetica" do
17
23
  @pdf.draw_text("Blah", :at => [100,100])
18
24
  text = PDF::Inspector::Text.analyze(@pdf.render)
@@ -97,23 +103,27 @@ describe "#draw_text" do
97
103
  it "should raise an exception when a utf-8 incompatible string is rendered" do
98
104
  str = "Blah \xDD"
99
105
  str.force_encoding("ASCII-8BIT")
100
- lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(ArgumentError)
106
+ lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(
107
+ Prawn::Errors::IncompatibleStringEncoding)
101
108
  end
102
109
  it "should not raise an exception when a shift-jis string is rendered" do
103
110
  datafile = "#{Prawn::BASEDIR}/data/shift_jis_text.txt"
104
111
  sjis_str = File.open(datafile, "r:shift_jis") { |f| f.gets }
105
112
  @pdf.font("#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf")
106
- lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.not.raise(ArgumentError)
113
+ lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.not.raise(
114
+ Prawn::Errors::IncompatibleStringEncoding)
107
115
  end
108
116
  else
109
117
  # Handle non utf-8 string encodings in a sane way on non-M17N aware VMs
110
118
  it "should raise an exception when a corrupt utf-8 string is rendered" do
111
119
  str = "Blah \xDD"
112
- lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(ArgumentError)
120
+ lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(
121
+ Prawn::Errors::IncompatibleStringEncoding)
113
122
  end
114
123
  it "should raise an exception when a shift-jis string is rendered" do
115
124
  sjis_str = File.read("#{Prawn::BASEDIR}/data/shift_jis_text.txt")
116
- lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.raise(ArgumentError)
125
+ lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.raise(
126
+ Prawn::Errors::IncompatibleStringEncoding)
117
127
  end
118
128
  end
119
129
  end
@@ -2,9 +2,102 @@
2
2
 
3
3
  require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
4
 
5
+ describe "Text::Box#nothing_printed?" do
6
+ it "should be true when nothing printed" do
7
+ create_pdf
8
+ string = "Hello world, how are you?\nI'm fine, thank you."
9
+ text_box = Prawn::Text::Box.new(string,
10
+ :height => 2,
11
+ :document => @pdf)
12
+ text_box.render
13
+ text_box.nothing_printed?.should.be true
14
+ end
15
+ it "should be false when something printed" do
16
+ create_pdf
17
+ string = "Hello world, how are you?\nI'm fine, thank you."
18
+ text_box = Prawn::Text::Box.new(string,
19
+ :height => 14,
20
+ :document => @pdf)
21
+ text_box.render
22
+ text_box.nothing_printed?.should.be false
23
+ end
24
+ end
25
+
26
+ describe "Text::Box#everything_printed?" do
27
+ it "should be false when not everything printed" do
28
+ create_pdf
29
+ string = "Hello world, how are you?\nI'm fine, thank you."
30
+ text_box = Prawn::Text::Box.new(string,
31
+ :height => 14,
32
+ :document => @pdf)
33
+ text_box.render
34
+ text_box.everything_printed?.should.be false
35
+ end
36
+ it "should be true when everything printed" do
37
+ create_pdf
38
+ string = "Hello world, how are you?\nI'm fine, thank you."
39
+ text_box = Prawn::Text::Box.new(string,
40
+ :document => @pdf)
41
+ text_box.render
42
+ text_box.everything_printed?.should.be true
43
+ end
44
+ end
45
+
46
+ describe "Text::Box#line_gap" do
47
+ it "should equal the line gap of the font when using a single " +
48
+ "font and font size" do
49
+ create_pdf
50
+ string = "Hello world, how are you?\nI'm fine, thank you."
51
+ text_box = Prawn::Text::Box.new(string,
52
+ :document => @pdf)
53
+ text_box.render
54
+ text_box.line_gap.should.be.close(@pdf.font.line_gap, 0.0001)
55
+ end
56
+ end
57
+
58
+ describe "Text::Box" do
59
+ it "should be able to set text direction document-wide" do
60
+ create_pdf
61
+ @pdf.text_direction(:rtl)
62
+ @pdf.text_direction = :rtl
63
+ string = "Hello world, how are you?\nI'm fine, thank you."
64
+ text_box = Prawn::Text::Box.new(string,
65
+ :document => @pdf)
66
+ text_box.render
67
+ text = PDF::Inspector::Text.analyze(@pdf.render)
68
+ text.strings[0].should == "?uoy era woh ,dlrow olleH"
69
+ text.strings[1].should == ".uoy knaht ,enif m'I"
70
+ end
71
+
72
+ it "should be able to reverse multi-byte text" do
73
+ create_pdf
74
+ @pdf.text_direction(:rtl)
75
+ @pdf.text_direction = :rtl
76
+ @pdf.text_direction = :rtl
77
+ @pdf.font("#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf", :size => 16) do
78
+ @pdf.text "写个小"
79
+ end
80
+ text = PDF::Inspector::Text.analyze(@pdf.render)
81
+ text.strings[0].should == "小个写"
82
+ end
83
+
84
+ it "option should be able to override document-wide text direction" do
85
+ create_pdf
86
+ @pdf.text_direction = :rtl
87
+ string = "Hello world, how are you?\nI'm fine, thank you."
88
+ text_box = Prawn::Text::Box.new(string,
89
+ :document => @pdf,
90
+ :direction => :ltr)
91
+ text_box.render
92
+ text = PDF::Inspector::Text.analyze(@pdf.render)
93
+ text.strings[0].should == "Hello world, how are you?"
94
+ text.strings[1].should == "I'm fine, thank you."
95
+ end
96
+ end
97
+
5
98
  describe "Text::Box" do
6
99
 
7
- it "should be able to set leading document wide" do
100
+ it "should be able to set leading document-wide" do
8
101
  create_pdf
9
102
  @pdf.default_leading(7)
10
103
  @pdf.default_leading = 7
@@ -13,7 +106,7 @@ describe "Text::Box" do
13
106
  text_box.leading.should == 7
14
107
  end
15
108
 
16
- it "option should be able to override document wide leading" do
109
+ it "option should be able to override document-wide leading" do
17
110
  create_pdf
18
111
  @pdf.default_leading = 7
19
112
  text_box = Prawn::Text::Box.new("hello world",
@@ -27,49 +120,67 @@ describe "Text::Box" do
27
120
  end
28
121
  end
29
122
 
30
- describe "Text::Box#extensions" do
31
- it "should be able to override default line wrapping" do
32
- create_pdf
33
- Prawn::Text::Box.extensions << TestWrapOverride
34
- @pdf.text_box("hello world", {})
35
- text = PDF::Inspector::Text.analyze(@pdf.render)
36
- text.strings[0].should == "all your base are belong to us"
37
- Prawn::Text::Box.extensions.delete(TestWrapOverride)
38
- end
39
- end
40
-
41
123
  describe "Text::Box#render with :align => :justify" do
42
124
  it "should draw the word spacing to the document" do
43
125
  create_pdf
44
- string = "hello world " * 10
126
+ string = "hello world " * 20
45
127
  options = { :document => @pdf, :align => :justify }
46
128
  text_box = Prawn::Text::Box.new(string, options)
47
129
  text_box.render
48
130
  contents = PDF::Inspector::Text.analyze(@pdf.render)
49
131
  contents.word_spacing[0].should.be > 0
50
132
  end
133
+ it "should not justify the last line of a paragraph" do
134
+ create_pdf
135
+ string = "hello world "
136
+ options = { :document => @pdf, :align => :justify }
137
+ text_box = Prawn::Text::Box.new(string, options)
138
+ text_box.render
139
+ contents = PDF::Inspector::Text.analyze(@pdf.render)
140
+ contents.word_spacing.should.be.empty
141
+ end
142
+ end
143
+
144
+ describe "Text::Box" do
145
+ it "should only require enough space for the descender and the ascender " +
146
+ "when determining whether a line can fit" do
147
+ create_pdf
148
+ text = "Oh hai text rect"
149
+ options = { :document => @pdf, :height => @pdf.font.ascender + @pdf.font.descender }
150
+ text_box = Prawn::Text::Box.new(text, options)
151
+ text_box.render
152
+ text_box.text.should == "Oh hai text rect"
153
+
154
+ text = "Oh hai text rect\nOh hai text rect"
155
+ options = { :document => @pdf, :height => @pdf.font.height + @pdf.font.ascender + @pdf.font.descender }
156
+ text_box = Prawn::Text::Box.new(text, options)
157
+ text_box.render
158
+ text_box.text.should == "Oh hai text rect\nOh hai text rect"
159
+ end
51
160
  end
52
161
 
53
162
  describe "Text::Box#height without leading" do
54
- it "should equal the sum of the height of each line" do
163
+ it "should equal the sum of the height of each line, " +
164
+ "not including the space below the last line" do
55
165
  create_pdf
56
166
  text = "Oh hai text rect.\nOh hai text rect."
57
167
  options = { :document => @pdf }
58
168
  text_box = Prawn::Text::Box.new(text, options)
59
169
  text_box.render
60
- text_box.height.should == @pdf.font.height * 2
170
+ text_box.height.should.be.close(@pdf.font.height * 2 - @pdf.font.line_gap, 0.001)
61
171
  end
62
172
  end
63
173
 
64
174
  describe "Text::Box#height with leading" do
65
- it "should equal the sum of the height of each line" do
175
+ it "should equal the sum of the height of each line plus leading, " +
176
+ "but not including the space below the last line" do
66
177
  create_pdf
67
178
  text = "Oh hai text rect.\nOh hai text rect."
68
179
  leading = 12
69
180
  options = { :document => @pdf, :leading => leading }
70
181
  text_box = Prawn::Text::Box.new(text, options)
71
182
  text_box.render
72
- text_box.height.should == @pdf.font.height * 2 + leading
183
+ text_box.height.should.be.close((@pdf.font.height + leading) * 2 - @pdf.font.line_gap - leading, 0.001)
73
184
  end
74
185
  end
75
186
 
@@ -142,7 +253,25 @@ describe "Text::Box#render(:dry_run => true)" do
142
253
  @options = { :document => @pdf }
143
254
  text_box = Prawn::Text::Box.new(@text, @options)
144
255
  text_box.render(:dry_run => true)
145
- lambda { text_box.render }.should.not.raise(ArgumentError)
256
+ lambda { text_box.render }.should.not.raise(
257
+ Prawn::Errors::IncompatibleStringEncoding)
258
+ end
259
+ end
260
+
261
+ describe "Text::Box#render(:valign => :bottom)" do
262
+ it "#at should be the same from one dry run to the next" do
263
+ create_pdf
264
+ text = "this is center text " * 12
265
+ options = { :width => 162,
266
+ :valign => :bottom,
267
+ :document => @pdf }
268
+ text_box = Prawn::Text::Box.new(text, options)
269
+
270
+ text_box.render(:dry_run => true)
271
+ original_at = text_box.at.dup
272
+
273
+ text_box.render(:dry_run => true)
274
+ text_box.at.should == original_at
146
275
  end
147
276
  end
148
277
 
@@ -303,15 +432,50 @@ describe "Text::Box#render with :rotate option of 30)" do
303
432
  end
304
433
 
305
434
  describe "Text::Box default height" do
435
+ before(:each) { create_pdf }
436
+
306
437
  it "should be the height from the bottom bound to document.y" do
307
- create_pdf
308
438
  target_height = @pdf.y - @pdf.bounds.bottom
309
439
  @text = "Oh hai\n" * 60
310
- @options = { :document => @pdf }
311
- text_box = Prawn::Text::Box.new(@text, @options)
440
+ text_box = Prawn::Text::Box.new(@text, :document => @pdf)
312
441
  text_box.render
313
442
  text_box.height.should.be.close(target_height, @pdf.font.height)
314
443
  end
444
+
445
+ it "should use the margin-box bottom if only in a stretchy bbox" do
446
+ @pdf.bounding_box([0, @pdf.cursor], :width => @pdf.bounds.width) do
447
+ target_height = @pdf.y - @pdf.bounds.bottom
448
+ @text = "Oh hai\n" * 60
449
+ text_box = Prawn::Text::Box.new(@text, :document => @pdf)
450
+ text_box.render
451
+ text_box.height.should.be.close(target_height, @pdf.font.height)
452
+ end
453
+ end
454
+
455
+ it "should use the parent-box bottom if in a stretchy bbox and " +
456
+ "overflow is :expand, even with an explicit height"do
457
+ @pdf.bounding_box([0, @pdf.cursor], :width => @pdf.bounds.width) do
458
+ target_height = @pdf.y - @pdf.bounds.bottom
459
+ @text = "Oh hai\n" * 60
460
+ text_box = Prawn::Text::Box.new(@text, :document => @pdf,
461
+ :height => 100, :overflow => :expand)
462
+ text_box.render
463
+ text_box.height.should.be.close(target_height, @pdf.font.height)
464
+ end
465
+ end
466
+
467
+ it "should use the innermost non-stretchy bbox, not the margin box" do
468
+ @pdf.bounding_box([0, @pdf.cursor], :width => @pdf.bounds.width,
469
+ :height => 200) do
470
+ @pdf.bounding_box([0, @pdf.cursor], :width => @pdf.bounds.width) do
471
+ @text = "Oh hai\n" * 60
472
+ text_box = Prawn::Text::Box.new(@text, :document => @pdf)
473
+ text_box.render
474
+ text_box.height.should.be.close(200, @pdf.font.height)
475
+ end
476
+ end
477
+ end
478
+
315
479
  end
316
480
 
317
481
  describe "Text::Box default at" do
@@ -337,8 +501,10 @@ describe "Text::Box with text than can fit in the box" do
337
501
  }
338
502
  end
339
503
 
340
- it "printed text should match requested text, except for trailing or leading white space and that spaces may be replaced by newlines" do
341
- text_box = Prawn::Text::Box.new(@text, @options)
504
+ it "printed text should match requested text, except that preceding and " +
505
+ "trailing white space will be stripped from each line, and newlines may " +
506
+ "be inserted" do
507
+ text_box = Prawn::Text::Box.new(" " + @text, @options)
342
508
  text_box.render
343
509
  text_box.text.gsub("\n", " ").should == @text.strip
344
510
  end
@@ -356,24 +522,72 @@ describe "Text::Box with text than can fit in the box" do
356
522
  end
357
523
  end
358
524
 
359
- describe "Text::Box with text than can fit in the box with :ellipses overflow and :valign => :bottom" do
360
- it "should not print ellipses" do
525
+ describe "Text::Box with text that fits exactly in the box" do
526
+ before(:each) do
361
527
  create_pdf
362
- @text = "Oh hai text rect. " * 10
528
+ @lines = 3
529
+ @interlines = @lines - 1
530
+ @text = (1..@lines).to_a.join("\n")
363
531
  @options = {
364
532
  :width => 162.0,
365
- :height => 162.0,
366
- :overflow => :ellipses,
367
- :valign => :bottom,
533
+ :height => @pdf.font.ascender + @pdf.font.height * @interlines + @pdf.font.descender,
368
534
  :document => @pdf
369
535
  }
370
- @text_box = Prawn::Text::Box.new(@text, @options)
371
- @text_box.render
372
- @text_box.text.should.not =~ /\.\.\./
373
536
  end
374
- end
537
+
538
+ it "should have the expected height" do
539
+ expected_height = @options.delete(:height)
540
+ text_box = Prawn::Text::Box.new(@text, @options)
541
+ text_box.render
542
+ text_box.height.should.be.close(expected_height, 0.0001)
543
+ end
544
+
545
+ it "should print everything" do
546
+ text_box = Prawn::Text::Box.new(@text, @options)
547
+ text_box.render
548
+ text_box.text.should == @text
549
+ end
550
+
551
+ describe "with leading" do
552
+ before(:each) do
553
+ @options[:leading] = 15
554
+ end
555
+
556
+ it "should not overflow when enough height is added" do
557
+ @options[:height] += @options[:leading] * @interlines
558
+ text_box = Prawn::Text::Box.new(@text, @options)
559
+ text_box.render
560
+ text_box.text.should == @text
561
+ end
562
+
563
+ it "should overflow when insufficient height is added" do
564
+ @options[:height] += @options[:leading] * @interlines - 1
565
+ text_box = Prawn::Text::Box.new(@text, @options)
566
+ text_box.render
567
+ text_box.text.should.not == @text
568
+ end
569
+ end
570
+
571
+ describe "with negative leading" do
572
+ before(:each) do
573
+ @options[:leading] = -4
574
+ end
375
575
 
576
+ it "should not overflow when enough height is removed" do
577
+ @options[:height] += @options[:leading] * @interlines
578
+ text_box = Prawn::Text::Box.new(@text, @options)
579
+ text_box.render
580
+ text_box.text.should == @text
581
+ end
376
582
 
583
+ it "should overflow when too much height is removed" do
584
+ @options[:height] += @options[:leading] * @interlines - 1
585
+ text_box = Prawn::Text::Box.new(@text, @options)
586
+ text_box.render
587
+ text_box.text.should.not == @text
588
+ end
589
+ end
590
+ end
377
591
 
378
592
  describe "Text::Box printing UTF-8 string with higher bit characters" do
379
593
  before(:each) do
@@ -407,9 +621,10 @@ describe "Text::Box printing UTF-8 string with higher bit characters" do
407
621
  remaining_text = @text_box.render
408
622
  lambda {
409
623
  @pdf.text_box(remaining_text, :document => @pdf)
410
- }.should.not.raise(ArgumentError)
624
+ }.should.not.raise(Prawn::Errors::IncompatibleStringEncoding)
411
625
  end
412
626
  end
627
+
413
628
  describe "when using an AFM font" do
414
629
  it "unprinted text should be in WinAnsi encoding" do
415
630
  remaining_text = @text_box.render
@@ -420,15 +635,14 @@ describe "Text::Box printing UTF-8 string with higher bit characters" do
420
635
  remaining_text = @text_box.render
421
636
  lambda {
422
637
  @pdf.text_box(remaining_text, :document => @pdf)
423
- }.should.raise(ArgumentError)
638
+ }.should.raise(Prawn::Errors::IncompatibleStringEncoding)
424
639
  lambda {
425
640
  @pdf.text_box(remaining_text, :skip_encoding => true,
426
641
  :document => @pdf)
427
- }.should.not.raise(ArgumentError)
642
+ }.should.not.raise(Prawn::Errors::IncompatibleStringEncoding)
428
643
  end
429
644
  end
430
645
  end
431
-
432
646
 
433
647
  describe "Text::Box with more text than can fit in the box" do
434
648
  before(:each) do
@@ -447,16 +661,12 @@ describe "Text::Box with more text than can fit in the box" do
447
661
  @options[:overflow] = :truncate
448
662
  @text_box = Prawn::Text::Box.new(@text, @options)
449
663
  end
450
- it "should not display ellipses" do
451
- @text_box.render
452
- @text_box.text.should.not =~ /\.\.\./
453
- end
454
664
  it "should be truncated" do
455
665
  @text_box.render
456
666
  @text_box.text.gsub("\n", " ").should.not == @text.strip
457
667
  end
458
668
  it "render should not return an empty string because some text remains unprinted" do
459
- @text_box.render.should.not == ""
669
+ @text_box.render.should.not.be.empty
460
670
  end
461
671
  it "#height should be no taller than the specified height" do
462
672
  @text_box.render
@@ -484,17 +694,17 @@ describe "Text::Box with more text than can fit in the box" do
484
694
  end
485
695
  end
486
696
 
487
- context "ellipses overflow" do
488
- before(:each) do
489
- @options[:overflow] = :ellipses
697
+ context "truncated with text and size taken from the manual" do
698
+ it "should return the right text" do
699
+ @text = "This is the beginning of the text. It will be cut somewhere and " +
700
+ "the rest of the text will procede to be rendered this time by " +
701
+ "calling another method." + " . " * 50
702
+ @options[:width] = 300
703
+ @options[:height] = 50
704
+ @options[:size] = 18
490
705
  @text_box = Prawn::Text::Box.new(@text, @options)
491
- end
492
- it "should display ellipses" do
493
- @text_box.render
494
- @text_box.text.should =~ /\.\.\./
495
- end
496
- it "render should not return an empty string because some text remains unprinted" do
497
- @text_box.render.should.not == ""
706
+ remaining_text = @text_box.render
707
+ remaining_text.should == "text will procede to be rendered this time by calling another method. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
498
708
  end
499
709
  end
500
710
 
@@ -530,6 +740,38 @@ describe "Text::Box with more text than can fit in the box" do
530
740
  @text_box.render.should == ""
531
741
  end
532
742
  end
743
+
744
+ context "shrink_to_fit overflow" do
745
+ it "should not drop below the minimum font size" do
746
+ @options[:overflow] = :shrink_to_fit
747
+ @options[:min_font_size] = 10.1
748
+ @text_box = Prawn::Text::Box.new(@text, @options)
749
+ @text_box.render
750
+
751
+ text = PDF::Inspector::Text.analyze(@pdf.render)
752
+ text.font_settings[0][:size].should == 10.1
753
+ end
754
+ end
755
+ end
756
+
757
+ describe "Text::Box with enough space to fit the text but using the " +
758
+ "shrink_to_fit overflow" do
759
+ it "should not shrink the text when there is no need to" do
760
+ create_pdf
761
+ @bounding_height = 162.0
762
+ @options = {
763
+ :width => 162.0,
764
+ :height => @bounding_height,
765
+ :overflow => :shrink_to_fit,
766
+ :min_font_size => 5,
767
+ :document => @pdf
768
+ }
769
+ @text_box = Prawn::Text::Box.new("hello\nworld", @options)
770
+ @text_box.render
771
+
772
+ text = PDF::Inspector::Text.analyze(@pdf.render)
773
+ text.font_settings[0][:size].should == 12
774
+ end
533
775
  end
534
776
 
535
777
  describe "Text::Box with a solid block of Chinese characters" do
@@ -545,13 +787,12 @@ describe "Text::Box with a solid block of Chinese characters" do
545
787
  @options[:overflow] = :truncate
546
788
  text_box = Prawn::Text::Box.new(@text, @options)
547
789
  text_box.render
548
- text_box.text.gsub("\n", "").should == @text.strip
790
+ text_box.text.gsub("\n", "").should == @text
549
791
  end
550
792
  end
551
793
 
552
794
 
553
795
  describe "drawing bounding boxes" do
554
-
555
796
  before(:each) { create_pdf }
556
797
 
557
798
  it "should restore the margin box when bounding box exits" do
@@ -562,7 +803,6 @@ describe "drawing bounding boxes" do
562
803
  @pdf.bounds.should == margin_box
563
804
 
564
805
  end
565
-
566
806
  end
567
807
 
568
808
 
@@ -703,7 +943,7 @@ describe "Text::Box wrapping" do
703
943
 
704
944
  expected = "©" * 25 + "\n" + "©" * 5
705
945
  @pdf.font.normalize_encoding!(expected)
706
-
946
+ expected = expected.force_encoding("utf-8") if expected.respond_to?(:force_encoding)
707
947
  text_box.text.should == expected
708
948
  end
709
949
 
@@ -722,21 +962,20 @@ describe "Text::Box wrapping" do
722
962
 
723
963
  results_with_accent.first_line.length.should == results_without_accent.first_line.length
724
964
  end
725
-
726
965
  end
727
966
 
728
- def reduce_precision(float)
729
- ("%.5f" % float).to_f
967
+ describe "Text::Box#render with :mode option" do
968
+ it "should alter the text rendering mode of the document" do
969
+ create_pdf
970
+ string = "hello world"
971
+ options = { :document => @pdf, :mode => :fill_stroke }
972
+ text_box = Prawn::Text::Box.new(string, options)
973
+ text_box.render
974
+ contents = PDF::Inspector::Text.analyze(@pdf.render)
975
+ contents.text_rendering_mode.should == [2,0]
976
+ end
730
977
  end
731
978
 
732
- module TestWrapOverride
733
- def wrap(string)
734
- @text = nil
735
- @line_height = @document.font.height
736
- @descender = @document.font.descender
737
- @ascender = @document.font.ascender
738
- @baseline_y = -@ascender
739
- draw_line("all your base are belong to us")
740
- ""
741
- end
979
+ def reduce_precision(float)
980
+ ("%.5f" % float).to_f
742
981
  end