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,298 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "Text::Formatted::Fragment#space_count" do
6
+ it "should return the number of spaces in the fragment" do
7
+ create_pdf
8
+ format_state = { }
9
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world ",
10
+ format_state,
11
+ @pdf)
12
+ fragment.space_count.should == 2
13
+ end
14
+ it "should exclude trailing spaces from the count when " +
15
+ ":exclude_trailing_white_space => true" do
16
+ create_pdf
17
+ format_state = { :exclude_trailing_white_space => true }
18
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world ",
19
+ format_state,
20
+ @pdf)
21
+ fragment.space_count.should == 1
22
+ end
23
+ end
24
+
25
+ describe "Text::Formatted::Fragment#include_trailing_white_space!" do
26
+ it "should make the fragment include trailing white space" do
27
+ create_pdf
28
+ format_state = { :exclude_trailing_white_space => true }
29
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world ",
30
+ format_state,
31
+ @pdf)
32
+ fragment.space_count.should == 1
33
+ fragment.include_trailing_white_space!
34
+ fragment.space_count.should == 2
35
+ end
36
+ end
37
+
38
+ describe "Text::Formatted::Fragment#text" do
39
+ it "should return the fragment text" do
40
+ create_pdf
41
+ format_state = { }
42
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world ",
43
+ format_state,
44
+ @pdf)
45
+ fragment.text.should == "hello world "
46
+ end
47
+ it "should return the fragment text without trailing spaces when " +
48
+ ":exclude_trailing_white_space => true" do
49
+ create_pdf
50
+ format_state = { :exclude_trailing_white_space => true }
51
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world ",
52
+ format_state,
53
+ @pdf)
54
+ fragment.text.should == "hello world"
55
+ end
56
+ end
57
+
58
+ describe "Text::Formatted::Fragment#word_spacing=" do
59
+ before(:each) do
60
+ create_pdf
61
+ format_state = { :styles => [:bold, :italic],
62
+ :color => nil,
63
+ :link => nil,
64
+ :anchor => nil,
65
+ :font => nil,
66
+ :size => nil }
67
+ @fragment = Prawn::Text::Formatted::Fragment.new("hello world",
68
+ format_state,
69
+ @pdf)
70
+ @fragment.width = 100
71
+ @fragment.left = 50
72
+ @fragment.baseline = 200
73
+ @fragment.line_height = 27
74
+ @fragment.descender = 7
75
+ @fragment.ascender = 17
76
+ @fragment.word_spacing = 10
77
+ end
78
+
79
+ it "should account for word_spacing in #width" do
80
+ @fragment.width.should == 110
81
+ end
82
+ it "should account for word_spacing in #bounding_box" do
83
+ target_box = [50, 193, 160, 217]
84
+ @fragment.bounding_box.should == target_box
85
+ end
86
+ it "should account for word_spacing in #absolute_bounding_box" do
87
+ target_box = [50, 193, 160, 217]
88
+ target_box[0] += @pdf.bounds.absolute_left
89
+ target_box[1] += @pdf.bounds.absolute_bottom
90
+ target_box[2] += @pdf.bounds.absolute_left
91
+ target_box[3] += @pdf.bounds.absolute_bottom
92
+ @fragment.absolute_bounding_box.should == target_box
93
+ end
94
+ it "should account for word_spacing in #underline_points" do
95
+ y = 198.75
96
+ target_points = [[50, y], [160, y]]
97
+ @fragment.underline_points.should == target_points
98
+ end
99
+ it "should account for word_spacing in #strikethrough_points" do
100
+ y = 200 + @fragment.ascender * 0.3
101
+ target_points = [[50, y], [160, y]]
102
+ @fragment.strikethrough_points.should == target_points
103
+ end
104
+ end
105
+
106
+ describe "Text::Formatted::Fragment" do
107
+ before(:each) do
108
+ create_pdf
109
+ format_state = { :styles => [:bold, :italic],
110
+ :color => nil,
111
+ :link => nil,
112
+ :anchor => nil,
113
+ :font => nil,
114
+ :size => nil }
115
+ @fragment = Prawn::Text::Formatted::Fragment.new("hello world",
116
+ format_state,
117
+ @pdf)
118
+ @fragment.width = 100
119
+ @fragment.left = 50
120
+ @fragment.baseline = 200
121
+ @fragment.line_height = 27
122
+ @fragment.descender = 7
123
+ @fragment.ascender = 17
124
+ end
125
+
126
+ describe "#width" do
127
+ it "should return the width" do
128
+ @fragment.width.should == 100
129
+ end
130
+ end
131
+
132
+ describe "#styles" do
133
+ it "should return the styles array" do
134
+ @fragment.styles.should == [:bold, :italic]
135
+ end
136
+ it "should never return nil" do
137
+ format_state = { :styles => nil,
138
+ :color => nil,
139
+ :link => nil,
140
+ :anchor => nil,
141
+ :font => nil,
142
+ :size => nil }
143
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world",
144
+ format_state,
145
+ @pdf)
146
+ fragment.styles.should == []
147
+ end
148
+ end
149
+
150
+ describe "#line_height" do
151
+ it "should return the line_height" do
152
+ @fragment.line_height.should == 27
153
+ end
154
+ end
155
+
156
+ describe "#ascender" do
157
+ it "should return the ascender" do
158
+ @fragment.ascender.should == 17
159
+ end
160
+ end
161
+
162
+ describe "#descender" do
163
+ it "should return the descender" do
164
+ @fragment.descender.should == 7
165
+ end
166
+ end
167
+
168
+ describe "#y_offset" do
169
+ it "should be zero" do
170
+ @fragment.y_offset.should == 0
171
+ end
172
+ end
173
+
174
+ describe "#bounding_box" do
175
+ it "should return the bounding box surrounding the fragment" do
176
+ target_box = [50, 193, 150, 217]
177
+ @fragment.bounding_box.should == target_box
178
+ end
179
+ end
180
+
181
+ describe "#absolute_bounding_box" do
182
+ it "should return the bounding box surrounding the fragment" +
183
+ " in absolute coordinates" do
184
+ target_box = [50, 193, 150, 217]
185
+ target_box[0] += @pdf.bounds.absolute_left
186
+ target_box[1] += @pdf.bounds.absolute_bottom
187
+ target_box[2] += @pdf.bounds.absolute_left
188
+ target_box[3] += @pdf.bounds.absolute_bottom
189
+ @fragment.absolute_bounding_box.should == target_box
190
+ end
191
+ end
192
+
193
+ describe "#underline_points" do
194
+ it "should define a line under the fragment" do
195
+ y = 198.75
196
+ target_points = [[50, y], [150, y]]
197
+ @fragment.underline_points.should == target_points
198
+ end
199
+ end
200
+
201
+ describe "#strikethrough_points" do
202
+ it "should define a line through the fragment" do
203
+ y = 200 + @fragment.ascender * 0.3
204
+ target_points = [[50, y], [150, y]]
205
+ @fragment.strikethrough_points.should == target_points
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "Text::Formatted::Fragment that is a subscript" do
211
+ before(:each) do
212
+ create_pdf
213
+ format_state = { :styles => [:subscript],
214
+ :color => nil,
215
+ :link => nil,
216
+ :anchor => nil,
217
+ :font => nil,
218
+ :size => nil }
219
+ @fragment = Prawn::Text::Formatted::Fragment.new("hello world",
220
+ format_state,
221
+ @pdf)
222
+ @fragment.line_height = 27
223
+ @fragment.descender = 7
224
+ @fragment.ascender = 17
225
+ end
226
+ describe "#subscript?" do
227
+ it "should be_true" do
228
+ @fragment.should be_subscript
229
+ end
230
+ end
231
+ describe "#y_offset" do
232
+ it "should return a negative value" do
233
+ @fragment.y_offset.should be < 0
234
+ end
235
+ end
236
+ end
237
+
238
+ describe "Text::Formatted::Fragment that is a superscript" do
239
+ before(:each) do
240
+ create_pdf
241
+ format_state = { :styles => [:superscript],
242
+ :color => nil,
243
+ :link => nil,
244
+ :anchor => nil,
245
+ :font => nil,
246
+ :size => nil }
247
+ @fragment = Prawn::Text::Formatted::Fragment.new("hello world",
248
+ format_state,
249
+ @pdf)
250
+ @fragment.line_height = 27
251
+ @fragment.descender = 7
252
+ @fragment.ascender = 17
253
+ end
254
+ describe "#superscript?" do
255
+ it "should be_true" do
256
+ @fragment.should be_superscript
257
+ end
258
+ end
259
+ describe "#y_offset" do
260
+ it "should return a positive value" do
261
+ @fragment.y_offset.should be > 0
262
+ end
263
+ end
264
+ end
265
+
266
+ describe "Text::Formatted::Fragment with :direction => :rtl" do
267
+ it "#text should be reversed" do
268
+ create_pdf
269
+ format_state = { :direction => :rtl }
270
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world",
271
+ format_state,
272
+ @pdf)
273
+ fragment.text.should == "dlrow olleh"
274
+ end
275
+ end
276
+
277
+ describe "Text::Formatted::Fragment default_direction=" do
278
+ it "should set the direction if there is no fragment level direction " +
279
+ "specification" do
280
+ create_pdf
281
+ format_state = { }
282
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world",
283
+ format_state,
284
+ @pdf)
285
+ fragment.default_direction = :rtl
286
+ fragment.direction.should == :rtl
287
+ end
288
+ it "should not set the direction if there is a fragment level direction " +
289
+ "specification" do
290
+ create_pdf
291
+ format_state = { :direction => :rtl }
292
+ fragment = Prawn::Text::Formatted::Fragment.new("hello world",
293
+ format_state,
294
+ @pdf)
295
+ fragment.default_direction = :ltr
296
+ fragment.direction.should == :rtl
297
+ end
298
+ end
@@ -0,0 +1,683 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "When drawing a line" do
6
+
7
+ before(:each) { create_pdf }
8
+
9
+ it "should draw a line from (100,600) to (100,500)" do
10
+ @pdf.line([100,600],[100,500])
11
+
12
+ line_drawing = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
13
+
14
+ line_drawing.points.should == [[100,600],[100,500]]
15
+ end
16
+
17
+ it "should draw two lines at (100,600) to (100,500) " +
18
+ "and (75,100) to (50,125)" do
19
+ @pdf.line(100,600,100,500)
20
+ @pdf.line(75,100,50,125)
21
+
22
+ line_drawing = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
23
+
24
+ line_drawing.points.should ==
25
+ [[100.0, 600.0], [100.0, 500.0], [75.0, 100.0], [50.0, 125.0]]
26
+ end
27
+
28
+ it "should properly set line width via line_width=" do
29
+ @pdf.line_width = 10
30
+ line = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
31
+ line.widths.first.should == 10
32
+ end
33
+
34
+ it "should properly set line width via line_width(width)" do
35
+ @pdf.line_width(10)
36
+ line = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
37
+ line.widths.first.should == 10
38
+ end
39
+
40
+ it "should carry the current line width settings over to new pages" do
41
+ @pdf.line_width(10)
42
+ @pdf.start_new_page
43
+ line = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
44
+ line.widths.length.should == 2
45
+ line.widths[1].should == 10
46
+ end
47
+
48
+ describe "(Horizontally)" do
49
+ it "should draw from [x1,pdf.y],[x2,pdf.y]" do
50
+ @pdf.horizontal_line(100,150)
51
+ @line = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
52
+ @line.points.should == [[100.0 + @pdf.bounds.absolute_left, @pdf.y],
53
+ [150.0 + @pdf.bounds.absolute_left, @pdf.y]]
54
+ end
55
+
56
+ it "should draw a line from (200, 250) to (300, 250)" do
57
+ @pdf.horizontal_line(200,300,:at => 250)
58
+ line_drawing = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
59
+ line_drawing.points.should == [[200,250],[300,250]]
60
+ end
61
+ end
62
+
63
+ describe "(Vertically)" do
64
+ it "should draw a line from (350, 300) to (350, 400)" do
65
+ @pdf.vertical_line(300,400,:at => 350)
66
+ line_drawing = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
67
+ line_drawing.points.should == [[350,300],[350,400]]
68
+ end
69
+ it "should require a y coordinate" do
70
+ lambda { @pdf.vertical_line(400,500) }.
71
+ should raise_error(ArgumentError)
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ describe "When drawing a polygon" do
78
+
79
+ before(:each) { create_pdf }
80
+
81
+ it "should draw each line passed to polygon()" do
82
+ @pdf.polygon([100,500],[100,400],[200,400])
83
+
84
+ line_drawing = PDF::Inspector::Graphics::Line.analyze(@pdf.render)
85
+ line_drawing.points.should == [[100,500],[100,400],[200,400],[100,500]]
86
+ end
87
+
88
+ end
89
+
90
+ describe "When drawing a rectangle" do
91
+
92
+ before(:each) { create_pdf }
93
+
94
+ it "should use a point, width, and height for coords" do
95
+ @pdf.rectangle [200,200], 50, 100
96
+
97
+ rectangles = PDF::Inspector::Graphics::Rectangle.
98
+ analyze(@pdf.render).rectangles
99
+ # PDF uses bottom left corner
100
+ rectangles[0][:point].should == [200,100]
101
+ rectangles[0][:width].should == 50
102
+ rectangles[0][:height].should == 100
103
+
104
+ end
105
+
106
+ end
107
+
108
+ describe "When drawing a curve" do
109
+
110
+ before(:each) { create_pdf }
111
+
112
+ it "should draw a bezier curve from 50,50 to 100,100" do
113
+ @pdf.move_to [50,50]
114
+ @pdf.curve_to [100,100],:bounds => [[20,90], [90,70]]
115
+ curve = PDF::Inspector::Graphics::Curve.analyze(@pdf.render)
116
+ curve.coords.should == [50.0, 50.0, 20.0, 90.0, 90.0, 70.0, 100.0, 100.0]
117
+ end
118
+
119
+ it "should draw a bezier curve from 100,100 to 50,50" do
120
+ @pdf.curve [100,100], [50,50], :bounds => [[20,90], [90,75]]
121
+ curve = PDF::Inspector::Graphics::Curve.analyze(@pdf.render)
122
+ curve.coords.should == [100.0, 100.0, 20.0, 90.0, 90.0, 75.0, 50.0, 50.0]
123
+ end
124
+
125
+
126
+ end
127
+
128
+ describe "When drawing a rounded rectangle" do
129
+ before(:each) do
130
+ create_pdf
131
+ @pdf.rounded_rectangle([50, 550], 50, 100, 10)
132
+ curve = PDF::Inspector::Graphics::Curve.analyze(@pdf.render)
133
+ curve_points = []
134
+ curve.coords.each_slice(2) {|p| curve_points << p}
135
+ @original_point = curve_points.shift
136
+ curves = []
137
+ curve_points.each_slice(3) {|c| curves << c}
138
+ line_points = PDF::Inspector::Graphics::Line.analyze(@pdf.render).points
139
+ line_points.shift
140
+ @all_coords = []
141
+ line_points.zip(curves).flatten.each_slice(2) {|p| @all_coords << p }
142
+ @all_coords.unshift @original_point
143
+ end
144
+
145
+ it "should draw a rectangle by connecting lines with rounded bezier curves" do
146
+ @all_coords.should == [[60.0, 550.0],[90.0, 550.0], [95.5228, 550.0],
147
+ [100.0, 545.5228], [100.0, 540.0], [100.0, 460.0],
148
+ [100.0, 454.4772], [95.5228, 450.0], [90.0, 450.0],
149
+ [60.0, 450.0], [54.4772, 450.0], [50.0, 454.4772],
150
+ [50.0, 460.0], [50.0, 540.0], [50.0, 545.5228],
151
+ [54.4772, 550.0], [60.0, 550.0]]
152
+ end
153
+
154
+ it "should start and end with the same point" do
155
+ @original_point.should == @all_coords.last
156
+ end
157
+
158
+
159
+ end
160
+
161
+ describe "When drawing an ellipse" do
162
+ before(:each) do
163
+ create_pdf
164
+ @pdf.ellipse [100,100], 25, 50
165
+ @curve = PDF::Inspector::Graphics::Curve.analyze(@pdf.render)
166
+ end
167
+
168
+ it "should use a Bézier approximation" do
169
+ @curve.coords.should ==
170
+ [125.0, 100.0,
171
+
172
+ 125.0, 127.6142,
173
+ 113.8071, 150,
174
+ 100.0, 150.0,
175
+
176
+ 86.1929, 150.0,
177
+ 75.0, 127.6142,
178
+ 75.0, 100.0,
179
+
180
+ 75.0, 72.3858,
181
+ 86.1929, 50.0,
182
+ 100.0, 50.0,
183
+
184
+ 113.8071, 50.0,
185
+ 125.0, 72.3858,
186
+ 125.0, 100.0,
187
+
188
+ 100.0, 100.0]
189
+ end
190
+
191
+ it "should move the pointer to the center of the ellipse after drawing" do
192
+ @curve.coords[-2..-1].should == [100,100]
193
+ end
194
+
195
+ end
196
+
197
+ describe "When drawing a circle" do
198
+ before(:each) do
199
+ create_pdf
200
+ @pdf.circle [100,100], 25
201
+ @pdf.ellipse [100,100], 25, 25
202
+ @curve = PDF::Inspector::Graphics::Curve.analyze(@pdf.render)
203
+ end
204
+
205
+ it "should stroke the same path as the equivalent ellipse" do
206
+ middle = @curve.coords.length / 2
207
+ @curve.coords[0...middle].should == @curve.coords[middle..-1]
208
+ end
209
+ end
210
+
211
+ describe "When filling" do
212
+ before(:each) { create_pdf }
213
+
214
+ it "should default to the f operator (nonzero winding number rule)" do
215
+ @pdf.renderer.expects(:add_content).with("f")
216
+ @pdf.fill
217
+ end
218
+
219
+ it "should use f* for :fill_rule => :even_odd" do
220
+ @pdf.renderer.expects(:add_content).with("f*")
221
+ @pdf.fill(:fill_rule => :even_odd)
222
+ end
223
+
224
+ it "should use b by default for fill_and_stroke (nonzero winding number)" do
225
+ @pdf.renderer.expects(:add_content).with("b")
226
+ @pdf.fill_and_stroke
227
+ end
228
+
229
+ it "should use b* for fill_and_stroke(:fill_rule => :even_odd)" do
230
+ @pdf.renderer.expects(:add_content).with("b*")
231
+ @pdf.fill_and_stroke(:fill_rule => :even_odd)
232
+ end
233
+ end
234
+
235
+ describe "When setting colors" do
236
+
237
+ before(:each) { create_pdf }
238
+
239
+ it "should set stroke colors" do
240
+ @pdf.stroke_color "ffcccc"
241
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
242
+ # 100% red, 80% green, 80% blue
243
+ colors.stroke_color.should == [1.0, 0.8, 0.8]
244
+ end
245
+
246
+ it "should set fill colors" do
247
+ @pdf.fill_color "ccff00"
248
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
249
+ # 80% red, 100% green, 0% blue
250
+ colors.fill_color.should == [0.8,1.0,0]
251
+ end
252
+
253
+ it "should reset the colors on each new page if they have been defined" do
254
+ @pdf.fill_color "ccff00"
255
+ #colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
256
+
257
+ # colors.fill_color_count.should == 2
258
+ # colors.stroke_color_count.should == 1
259
+ @pdf.start_new_page
260
+ @pdf.stroke_color "ff00cc"
261
+
262
+ #colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
263
+ # colors.fill_color_count.should == 3
264
+
265
+ @pdf.start_new_page
266
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
267
+ colors.fill_color_count.should == 3
268
+ colors.stroke_color_count.should == 2
269
+
270
+ colors.fill_color.should == [0.8,1.0,0.0]
271
+ colors.stroke_color.should == [1.0,0.0,0.8]
272
+ end
273
+
274
+ it "should set the color space when setting colors on new pages to please fussy readers" do
275
+ @pdf.stroke_color "000000"
276
+ @pdf.stroke { @pdf.rectangle([10, 10], 10, 10) }
277
+ @pdf.start_new_page
278
+ @pdf.stroke_color "000000"
279
+ @pdf.stroke { @pdf.rectangle([10, 10], 10, 10) }
280
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
281
+ colors.stroke_color_space_count[:DeviceRGB].should == 2
282
+ end
283
+ end
284
+
285
+ describe "Patterns" do
286
+ before(:each) { create_pdf }
287
+
288
+ describe 'linear gradients' do
289
+ it "should create a /Pattern resource" do
290
+ @pdf.fill_gradient [0, @pdf.bounds.height],
291
+ [@pdf.bounds.width, @pdf.bounds.height], 'FF0000', '0000FF'
292
+
293
+ grad = PDF::Inspector::Graphics::Pattern.analyze(@pdf.render)
294
+ pattern = grad.patterns.values.first
295
+
296
+ pattern.should_not be_nil
297
+ pattern[:Shading][:ShadingType].should == 2
298
+ pattern[:Shading][:Coords].should == [0, 0, @pdf.bounds.width, 0]
299
+ pattern[:Shading][:Function][:C0].zip([1, 0, 0]).all?{ |x1, x2|
300
+ (x1-x2).abs < 0.01
301
+ }.should be_true
302
+ pattern[:Shading][:Function][:C1].zip([0, 0, 1]).all?{ |x1, x2|
303
+ (x1-x2).abs < 0.01
304
+ }.should be_true
305
+ end
306
+
307
+ it "fill_gradient should set fill color to the pattern" do
308
+ @pdf.fill_gradient [0, @pdf.bounds.height],
309
+ [@pdf.bounds.width, @pdf.bounds.height], 'FF0000', '0000FF'
310
+
311
+ str = @pdf.render
312
+ str.should =~ %r{/Pattern\s+cs\s*/SP-?\d+\s+scn}
313
+ end
314
+
315
+ it "stroke_gradient should set stroke color to the pattern" do
316
+ @pdf.stroke_gradient [0, @pdf.bounds.height],
317
+ [@pdf.bounds.width, @pdf.bounds.height], 'FF0000', '0000FF'
318
+
319
+ str = @pdf.render
320
+ str.should =~ %r{/Pattern\s+CS\s*/SP-?\d+\s+SCN}
321
+ end
322
+ end
323
+
324
+ describe 'radial gradients' do
325
+ it "should create a /Pattern resource" do
326
+ @pdf.fill_gradient [0, @pdf.bounds.height], 10,
327
+ [@pdf.bounds.width, @pdf.bounds.height], 20, 'FF0000', '0000FF'
328
+
329
+ grad = PDF::Inspector::Graphics::Pattern.analyze(@pdf.render)
330
+ pattern = grad.patterns.values.first
331
+
332
+ pattern.should_not be_nil
333
+ pattern[:Shading][:ShadingType].should == 3
334
+ pattern[:Shading][:Coords].should == [0, 0, 10, @pdf.bounds.width, 0, 20]
335
+ pattern[:Shading][:Function][:C0].zip([1, 0, 0]).all?{ |x1, x2|
336
+ (x1-x2).abs < 0.01
337
+ }.should be_true
338
+ pattern[:Shading][:Function][:C1].zip([0, 0, 1]).all?{ |x1, x2|
339
+ (x1-x2).abs < 0.01
340
+ }.should be_true
341
+ end
342
+
343
+ it "fill_gradient should set fill color to the pattern" do
344
+ @pdf.fill_gradient [0, @pdf.bounds.height], 10,
345
+ [@pdf.bounds.width, @pdf.bounds.height], 20, 'FF0000', '0000FF'
346
+
347
+ str = @pdf.render
348
+ str.should =~ %r{/Pattern\s+cs\s*/SP-?\d+\s+scn}
349
+ end
350
+
351
+ it "stroke_gradient should set stroke color to the pattern" do
352
+ @pdf.stroke_gradient [0, @pdf.bounds.height], 10,
353
+ [@pdf.bounds.width, @pdf.bounds.height], 20, 'FF0000', '0000FF'
354
+
355
+ str = @pdf.render
356
+ str.should =~ %r{/Pattern\s+CS\s*/SP-?\d+\s+SCN}
357
+ end
358
+ end
359
+ end
360
+
361
+ describe "When using painting shortcuts" do
362
+ before(:each) { create_pdf }
363
+
364
+ it "should convert stroke_some_method(args) into some_method(args); stroke" do
365
+ @pdf.expects(:line_to).with([100,100])
366
+ @pdf.expects(:stroke)
367
+
368
+ @pdf.stroke_line_to [100,100]
369
+ end
370
+
371
+ it "should convert fill_some_method(args) into some_method(args); fill" do
372
+ @pdf.expects(:line_to).with([100,100])
373
+ @pdf.expects(:fill)
374
+
375
+ @pdf.fill_line_to [100,100]
376
+ end
377
+
378
+ it "should not break method_missing" do
379
+ lambda { @pdf.i_have_a_pretty_girlfriend_named_jia }.
380
+ should raise_error(NoMethodError)
381
+ end
382
+ end
383
+
384
+ describe "When using graphics states" do
385
+ before(:each) { create_pdf }
386
+
387
+ it "should add the right content on save_graphics_state" do
388
+ @pdf.renderer.expects(:add_content).with('q')
389
+
390
+ @pdf.save_graphics_state
391
+ end
392
+
393
+ it "should add the right content on restore_graphics_state" do
394
+ @pdf.renderer.expects(:add_content).with('Q')
395
+
396
+ @pdf.restore_graphics_state
397
+ end
398
+
399
+ it "should save and restore when save_graphics_state is used with a block" do
400
+ state = sequence "state"
401
+ @pdf.renderer.expects(:add_content).with('q').in_sequence(state)
402
+ @pdf.expects(:foo).in_sequence(state)
403
+ @pdf.renderer.expects(:add_content).with('Q').in_sequence(state)
404
+
405
+ @pdf.save_graphics_state do
406
+ @pdf.foo
407
+ end
408
+ end
409
+
410
+ it "should add the previous color space when restoring to a graphic state with different color space" do
411
+ @pdf.stroke_color '000000'
412
+ @pdf.save_graphics_state
413
+ @pdf.stroke_color 0, 0, 0, 0
414
+ @pdf.restore_graphics_state
415
+ @pdf.stroke_color 0, 0, 100, 0
416
+ @pdf.graphic_state.color_space.should == {:stroke=>:DeviceCMYK}
417
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
418
+ colors.color_space.should == :DeviceCMYK
419
+ colors.stroke_color_space_count[:DeviceCMYK].should == 2
420
+ end
421
+
422
+ it "should use the correct dash setting after restoring and starting new page" do
423
+ @pdf.dash 5
424
+ @pdf.save_graphics_state
425
+ @pdf.dash 10
426
+ @pdf.graphic_state.dash[:dash].should == 10
427
+ @pdf.restore_graphics_state
428
+ @pdf.start_new_page
429
+ @pdf.graphic_state.dash[:dash].should == 5
430
+ end
431
+
432
+ it "should round dash values to four decimal places" do
433
+ @pdf.dash 5.12345
434
+ @pdf.graphic_state.dash_setting.should == "[5.1235 5.1235] 0.0 d"
435
+ end
436
+
437
+ it "should raise an error when dash is called w. a zero length or space" do
438
+ expect { @pdf.dash(0) }.to raise_error(ArgumentError)
439
+ expect { @pdf.dash([0]) }.to raise_error(ArgumentError)
440
+ expect { @pdf.dash([0,0]) }.to raise_error(ArgumentError)
441
+ expect { @pdf.dash([0,0,0,1]) }.to raise_error(ArgumentError)
442
+ end
443
+
444
+ it "the current graphic state should keep track of previous unchanged settings" do
445
+ @pdf.stroke_color '000000'
446
+ @pdf.save_graphics_state
447
+ @pdf.dash 5
448
+ @pdf.save_graphics_state
449
+ @pdf.cap_style :round
450
+ @pdf.save_graphics_state
451
+ @pdf.fill_color 0, 0, 100, 0
452
+ @pdf.save_graphics_state
453
+
454
+ @pdf.graphic_state.stroke_color.should == "000000"
455
+ @pdf.graphic_state.join_style.should == :miter
456
+ @pdf.graphic_state.fill_color.should == [0, 0, 100, 0]
457
+ @pdf.graphic_state.cap_style.should == :round
458
+ @pdf.graphic_state.color_space.should == {:fill=>:DeviceCMYK, :stroke=>:DeviceRGB}
459
+ @pdf.graphic_state.dash.should == {:space=>5, :phase=>0, :dash=>5}
460
+ @pdf.graphic_state.line_width.should == 1
461
+ end
462
+
463
+
464
+
465
+ it "should not add extra graphic space closings when rendering multiple times" do
466
+ @pdf.render
467
+ state = PDF::Inspector::Graphics::State.analyze(@pdf.render)
468
+ state.save_graphics_state_count.should == 1
469
+ state.restore_graphics_state_count.should == 1
470
+ end
471
+
472
+ it "should add extra graphic state enclosings when content is added on multiple renderings" do
473
+ @pdf.render
474
+ @pdf.text "Adding a bit more content"
475
+ state = PDF::Inspector::Graphics::State.analyze(@pdf.render)
476
+ state.save_graphics_state_count.should == 2
477
+ state.restore_graphics_state_count.should == 2
478
+ end
479
+
480
+ it "adds extra graphic state enclosings when new settings are applied on multiple renderings" do
481
+ @pdf.render
482
+ @pdf.stroke_color 0, 0, 0, 0
483
+ state = PDF::Inspector::Graphics::State.analyze(@pdf.render)
484
+ state.save_graphics_state_count.should == 2
485
+ state.restore_graphics_state_count.should == 2
486
+ end
487
+
488
+
489
+ it "should raise_error error if closing an empty graphic stack" do
490
+ lambda {
491
+ @pdf.render
492
+ @pdf.restore_graphics_state
493
+ }.should raise_error(PDF::Core::Errors::EmptyGraphicStateStack)
494
+ end
495
+
496
+ it "should copy mutable attributes when passing a previous_state to the initializer" do
497
+ new_state = PDF::Core::GraphicState.new(@pdf.graphic_state)
498
+
499
+ [:color_space, :dash, :fill_color, :stroke_color].each do |attr|
500
+ new_state.send(attr).should == @pdf.graphic_state.send(attr)
501
+ new_state.send(attr).should_not equal(@pdf.graphic_state.send(attr))
502
+ end
503
+ end
504
+
505
+ it "should copy mutable attributes when duping" do
506
+ new_state = @pdf.graphic_state.dup
507
+
508
+ [:color_space, :dash, :fill_color, :stroke_color].each do |attr|
509
+ new_state.send(attr).should == @pdf.graphic_state.send(attr)
510
+ new_state.send(attr).should_not equal(@pdf.graphic_state.send(attr))
511
+ end
512
+ end
513
+ end
514
+
515
+ describe "When using transformation matrix" do
516
+ before(:each) { create_pdf }
517
+
518
+ # Note: The (approximate) number of significant decimal digits of precision in fractional
519
+ # part is 5 (PDF Reference, Third Edition, p. 706)
520
+
521
+ it "should send the right content on transformation_matrix" do
522
+ @pdf.renderer.expects(:add_content).with('1.00000 0.00000 0.12346 -1.00000 5.50000 20.00000 cm')
523
+ @pdf.transformation_matrix 1, 0, 0.123456789, -1.0, 5.5, 20
524
+ end
525
+
526
+ it "should use fixed digits with very small number" do
527
+ values = Array.new(6, 0.000000000001)
528
+ string = Array.new(6, "0.00000").join " "
529
+ @pdf.renderer.expects(:add_content).with("#{string} cm")
530
+ @pdf.transformation_matrix *values
531
+ end
532
+
533
+ it "should be received by the inspector" do
534
+ @pdf.transformation_matrix 1, 0, 0, -1, 5.5, 20
535
+ matrices = PDF::Inspector::Graphics::Matrix.analyze(@pdf.render)
536
+ matrices.matrices.should == [[1, 0, 0, -1, 5.5, 20]]
537
+ end
538
+
539
+ it "should save the graphics state inside the given block" do
540
+ values = Array.new(6, 0.000000000001)
541
+ string = Array.new(6, "0.00000").join " "
542
+ process = sequence "process"
543
+
544
+ @pdf.expects(:save_graphics_state).with().in_sequence(process)
545
+ @pdf.renderer.expects(:add_content).with("#{string} cm").in_sequence(process)
546
+ @pdf.expects(:do_something).with().in_sequence(process)
547
+ @pdf.expects(:restore_graphics_state).with().in_sequence(process)
548
+ @pdf.transformation_matrix(*values) do
549
+ @pdf.do_something
550
+ end
551
+ end
552
+
553
+ end
554
+
555
+ describe "When using transformations shortcuts" do
556
+ before(:each) do
557
+ create_pdf
558
+ @x, @y = 12, 54.32
559
+ @angle = 12.32
560
+ @cos = Math.cos(@angle * Math::PI / 180)
561
+ @sin = Math.sin(@angle * Math::PI / 180)
562
+ @factor = 0.12
563
+ end
564
+
565
+ describe "#rotate" do
566
+ it "should rotate" do
567
+ @pdf.expects(:transformation_matrix).with(@cos, @sin, -@sin, @cos, 0, 0)
568
+ @pdf.rotate(@angle)
569
+ end
570
+ end
571
+
572
+ describe "#rotate with :origin option" do
573
+ it "should rotate around the origin" do
574
+ x_prime = @x * @cos - @y * @sin
575
+ y_prime = @x * @sin + @y * @cos
576
+
577
+ @pdf.rotate(@angle, :origin => [@x, @y]) { @pdf.text('hello world') }
578
+
579
+ matrices = PDF::Inspector::Graphics::Matrix.analyze(@pdf.render)
580
+ matrices.matrices[0].should == [1, 0, 0, 1,
581
+ reduce_precision(@x - x_prime),
582
+ reduce_precision(@y - y_prime)]
583
+ matrices.matrices[1].should == [reduce_precision(@cos),
584
+ reduce_precision(@sin),
585
+ reduce_precision(-@sin),
586
+ reduce_precision(@cos), 0, 0]
587
+ end
588
+
589
+ it "should rotate around the origin in a document with a margin" do
590
+ @pdf = Prawn::Document.new
591
+
592
+ @pdf.rotate(@angle, :origin => [@x, @y]) { @pdf.text('hello world') }
593
+
594
+ x = @x + @pdf.bounds.absolute_left
595
+ y = @y + @pdf.bounds.absolute_bottom
596
+ x_prime = x * @cos - y * @sin
597
+ y_prime = x * @sin + y * @cos
598
+
599
+ matrices = PDF::Inspector::Graphics::Matrix.analyze(@pdf.render)
600
+ matrices.matrices[0].should == [1, 0, 0, 1,
601
+ reduce_precision(x - x_prime),
602
+ reduce_precision(y - y_prime)]
603
+ matrices.matrices[1].should == [reduce_precision(@cos),
604
+ reduce_precision(@sin),
605
+ reduce_precision(-@sin),
606
+ reduce_precision(@cos), 0, 0]
607
+ end
608
+
609
+ it "should raise_error BlockRequired if no block is given" do
610
+ lambda {
611
+ @pdf.rotate(@angle, :origin => [@x, @y])
612
+ }.should raise_error(Prawn::Errors::BlockRequired)
613
+ end
614
+
615
+ def reduce_precision(float)
616
+ ("%.5f" % float).to_f
617
+ end
618
+ end
619
+
620
+ describe "#translate" do
621
+ it "should translate" do
622
+ x, y = 12, 54.32
623
+ @pdf.expects(:transformation_matrix).with(1, 0, 0, 1, x, y)
624
+ @pdf.translate(x, y)
625
+ end
626
+ end
627
+
628
+ describe "#scale" do
629
+ it "should scale" do
630
+ @pdf.expects(:transformation_matrix).with(@factor, 0, 0, @factor, 0, 0)
631
+ @pdf.scale(@factor)
632
+ end
633
+ end
634
+
635
+ describe "#scale with :origin option" do
636
+ it "should scale from the origin" do
637
+ x_prime = @factor * @x
638
+ y_prime = @factor * @y
639
+
640
+ @pdf.scale(@factor, :origin => [@x, @y]) { @pdf.text('hello world') }
641
+
642
+ matrices = PDF::Inspector::Graphics::Matrix.analyze(@pdf.render)
643
+ matrices.matrices[0].should == [1, 0, 0, 1,
644
+ reduce_precision(@x - x_prime),
645
+ reduce_precision(@y - y_prime)]
646
+ matrices.matrices[1].should == [@factor, 0, 0, @factor, 0, 0]
647
+ end
648
+
649
+ it "should scale from the origin in a document with a margin" do
650
+ @pdf = Prawn::Document.new
651
+ x = @x + @pdf.bounds.absolute_left
652
+ y = @y + @pdf.bounds.absolute_bottom
653
+ x_prime = @factor * x
654
+ y_prime = @factor * y
655
+
656
+ @pdf.scale(@factor, :origin => [@x, @y]) { @pdf.text('hello world') }
657
+
658
+ matrices = PDF::Inspector::Graphics::Matrix.analyze(@pdf.render)
659
+ matrices.matrices[0].should == [1, 0, 0, 1,
660
+ reduce_precision(x - x_prime),
661
+ reduce_precision(y - y_prime)]
662
+ matrices.matrices[1].should == [@factor, 0, 0, @factor, 0, 0]
663
+ end
664
+
665
+ it "should raise_error BlockRequired if no block is given" do
666
+ lambda {
667
+ @pdf.scale(@factor, :origin => [@x, @y])
668
+ }.should raise_error(Prawn::Errors::BlockRequired)
669
+ end
670
+
671
+ def reduce_precision(float)
672
+ ("%.5f" % float).to_f
673
+ end
674
+ end
675
+
676
+ # describe "skew" do
677
+ # it "should skew" do
678
+ # a, b = 30, 50.2
679
+ # @pdf.expects(:transformation_matrix).with(1, Math.tan(a * Math::PI / 180), Math.tan(b * Math::PI / 180), 1, 0, 0)
680
+ # @pdf.skew(a, b)
681
+ # end
682
+ # end
683
+ end