alphasights-prawn 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. data/COPYING +340 -0
  2. data/HACKING +50 -0
  3. data/LICENSE +56 -0
  4. data/README +141 -0
  5. data/Rakefile +52 -0
  6. data/data/encodings/win_ansi.txt +29 -0
  7. data/data/fonts/Action Man.dfont +0 -0
  8. data/data/fonts/Activa.ttf +0 -0
  9. data/data/fonts/Chalkboard.ttf +0 -0
  10. data/data/fonts/Courier-Bold.afm +342 -0
  11. data/data/fonts/Courier-BoldOblique.afm +342 -0
  12. data/data/fonts/Courier-Oblique.afm +342 -0
  13. data/data/fonts/Courier.afm +342 -0
  14. data/data/fonts/DejaVuSans.ttf +0 -0
  15. data/data/fonts/Dustismo_Roman.ttf +0 -0
  16. data/data/fonts/Helvetica-Bold.afm +2827 -0
  17. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  18. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  19. data/data/fonts/Helvetica.afm +3051 -0
  20. data/data/fonts/MustRead.html +19 -0
  21. data/data/fonts/Symbol.afm +213 -0
  22. data/data/fonts/Times-Bold.afm +2588 -0
  23. data/data/fonts/Times-BoldItalic.afm +2384 -0
  24. data/data/fonts/Times-Italic.afm +2667 -0
  25. data/data/fonts/Times-Roman.afm +2419 -0
  26. data/data/fonts/ZapfDingbats.afm +225 -0
  27. data/data/fonts/comicsans.ttf +0 -0
  28. data/data/fonts/gkai00mp.ttf +0 -0
  29. data/data/images/16bit.alpha +0 -0
  30. data/data/images/16bit.dat +0 -0
  31. data/data/images/16bit.png +0 -0
  32. data/data/images/arrow.png +0 -0
  33. data/data/images/arrow2.png +0 -0
  34. data/data/images/barcode_issue.png +0 -0
  35. data/data/images/dice.alpha +0 -0
  36. data/data/images/dice.dat +0 -0
  37. data/data/images/dice.png +0 -0
  38. data/data/images/dice_interlaced.png +0 -0
  39. data/data/images/fractal.jpg +0 -0
  40. data/data/images/letterhead.jpg +0 -0
  41. data/data/images/page_white_text.alpha +0 -0
  42. data/data/images/page_white_text.dat +0 -0
  43. data/data/images/page_white_text.png +0 -0
  44. data/data/images/pigs.jpg +0 -0
  45. data/data/images/rails.dat +0 -0
  46. data/data/images/rails.png +0 -0
  47. data/data/images/ruport.png +0 -0
  48. data/data/images/ruport_data.dat +0 -0
  49. data/data/images/ruport_transparent.png +0 -0
  50. data/data/images/ruport_type0.png +0 -0
  51. data/data/images/stef.jpg +0 -0
  52. data/data/images/tru256.bmp +0 -0
  53. data/data/images/web-links.dat +1 -0
  54. data/data/images/web-links.png +0 -0
  55. data/data/pdfs/complex_template.pdf +0 -0
  56. data/data/pdfs/contains_ttf_font.pdf +0 -0
  57. data/data/pdfs/encrypted.pdf +0 -0
  58. data/data/pdfs/hexagon.pdf +61 -0
  59. data/data/pdfs/indirect_reference.pdf +86 -0
  60. data/data/pdfs/nested_pages.pdf +118 -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/examples/bounding_box/bounding_boxes.rb +43 -0
  66. data/examples/bounding_box/indentation.rb +34 -0
  67. data/examples/bounding_box/russian_boxes.rb +36 -0
  68. data/examples/bounding_box/stretched_nesting.rb +67 -0
  69. data/examples/builder/simple.rb +28 -0
  70. data/examples/example_helper.rb +4 -0
  71. data/examples/general/background.rb +23 -0
  72. data/examples/general/canvas.rb +15 -0
  73. data/examples/general/context_sensitive_headers.rb +37 -0
  74. data/examples/general/float.rb +11 -0
  75. data/examples/general/margin.rb +36 -0
  76. data/examples/general/measurement_units.rb +51 -0
  77. data/examples/general/metadata-info.rb +16 -0
  78. data/examples/general/multi_page_layout.rb +18 -0
  79. data/examples/general/outlines.rb +50 -0
  80. data/examples/general/page_geometry.rb +31 -0
  81. data/examples/general/page_numbering.rb +15 -0
  82. data/examples/general/repeaters.rb +47 -0
  83. data/examples/general/stamp.rb +41 -0
  84. data/examples/general/templates.rb +13 -0
  85. data/examples/graphics/basic_images.rb +23 -0
  86. data/examples/graphics/chunkable.rb +38 -0
  87. data/examples/graphics/cmyk.rb +12 -0
  88. data/examples/graphics/curves.rb +11 -0
  89. data/examples/graphics/hexagon.rb +13 -0
  90. data/examples/graphics/image_fit.rb +15 -0
  91. data/examples/graphics/image_flow.rb +37 -0
  92. data/examples/graphics/image_position.rb +17 -0
  93. data/examples/graphics/line.rb +32 -0
  94. data/examples/graphics/png_types.rb +22 -0
  95. data/examples/graphics/polygons.rb +16 -0
  96. data/examples/graphics/remote_images.rb +12 -0
  97. data/examples/graphics/rounded_polygons.rb +19 -0
  98. data/examples/graphics/rounded_rectangle.rb +20 -0
  99. data/examples/graphics/ruport_style_helpers.rb +19 -0
  100. data/examples/graphics/stroke_bounds.rb +20 -0
  101. data/examples/graphics/stroke_cap_and_join.rb +45 -0
  102. data/examples/graphics/stroke_dash.rb +42 -0
  103. data/examples/graphics/transformations.rb +52 -0
  104. data/examples/graphics/transparency.rb +26 -0
  105. data/examples/m17n/chinese_text_wrapping.rb +17 -0
  106. data/examples/m17n/euro.rb +15 -0
  107. data/examples/m17n/sjis.rb +28 -0
  108. data/examples/m17n/utf8.rb +13 -0
  109. data/examples/m17n/win_ansi_charset.rb +54 -0
  110. data/examples/security/hello_foo.rb +8 -0
  111. data/examples/table/bill.rb +53 -0
  112. data/examples/table/cell.rb +12 -0
  113. data/examples/table/checkerboard.rb +22 -0
  114. data/examples/table/header.rb +14 -0
  115. data/examples/table/inline_format_table.rb +12 -0
  116. data/examples/table/multi_page_table.rb +9 -0
  117. data/examples/table/simple_table.rb +24 -0
  118. data/examples/table/subtable.rb +12 -0
  119. data/examples/table/widths.rb +20 -0
  120. data/examples/text/alignment.rb +18 -0
  121. data/examples/text/character_spacing.rb +12 -0
  122. data/examples/text/dfont.rb +48 -0
  123. data/examples/text/family_based_styling.rb +24 -0
  124. data/examples/text/font_calculations.rb +91 -0
  125. data/examples/text/font_size.rb +33 -0
  126. data/examples/text/hyphenation.rb +45 -0
  127. data/examples/text/indent_paragraphs.rb +22 -0
  128. data/examples/text/inline_format.rb +103 -0
  129. data/examples/text/kerning.rb +30 -0
  130. data/examples/text/rotated.rb +98 -0
  131. data/examples/text/shaped_text_box.rb +31 -0
  132. data/examples/text/simple_text.rb +17 -0
  133. data/examples/text/simple_text_ttf.rb +17 -0
  134. data/examples/text/text_box.rb +88 -0
  135. data/examples/text/text_box_returning_excess.rb +51 -0
  136. data/examples/text/text_flow.rb +67 -0
  137. data/lib/prawn.rb +27 -0
  138. data/lib/prawn/canvas.rb +119 -0
  139. data/lib/prawn/chunkable.rb +37 -0
  140. data/lib/prawn/compatibility.rb +51 -0
  141. data/lib/prawn/core.rb +85 -0
  142. data/lib/prawn/core/annotations.rb +61 -0
  143. data/lib/prawn/core/byte_string.rb +9 -0
  144. data/lib/prawn/core/chunk.rb +36 -0
  145. data/lib/prawn/core/destinations.rb +90 -0
  146. data/lib/prawn/core/document_state.rb +78 -0
  147. data/lib/prawn/core/literal_string.rb +16 -0
  148. data/lib/prawn/core/name_tree.rb +165 -0
  149. data/lib/prawn/core/object_store.rb +236 -0
  150. data/lib/prawn/core/page.rb +179 -0
  151. data/lib/prawn/core/pdf_object.rb +108 -0
  152. data/lib/prawn/core/reference.rb +112 -0
  153. data/lib/prawn/core/text.rb +140 -0
  154. data/lib/prawn/core/text/formatted/arranger.rb +266 -0
  155. data/lib/prawn/core/text/formatted/line_wrap.rb +127 -0
  156. data/lib/prawn/core/text/formatted/wrap.rb +112 -0
  157. data/lib/prawn/core/text/line_wrap.rb +209 -0
  158. data/lib/prawn/core/text/wrap.rb +80 -0
  159. data/lib/prawn/document.rb +573 -0
  160. data/lib/prawn/document/bounding_box.rb +425 -0
  161. data/lib/prawn/document/graphics_state.rb +48 -0
  162. data/lib/prawn/document/internals.rb +170 -0
  163. data/lib/prawn/document/page_geometry.rb +136 -0
  164. data/lib/prawn/document/snapshot.rb +87 -0
  165. data/lib/prawn/document_builder.rb +51 -0
  166. data/lib/prawn/document_builder/command.rb +38 -0
  167. data/lib/prawn/document_builder/constructs.rb +2 -0
  168. data/lib/prawn/document_builder/constructs/flowing_text_construct.rb +18 -0
  169. data/lib/prawn/document_builder/constructs/path_construct.rb +9 -0
  170. data/lib/prawn/document_builder/layout.rb +25 -0
  171. data/lib/prawn/document_builder/modifications.rb +2 -0
  172. data/lib/prawn/document_builder/modifications/layout_modification.rb +9 -0
  173. data/lib/prawn/document_builder/modifications/path_modification.rb +9 -0
  174. data/lib/prawn/encoding.rb +121 -0
  175. data/lib/prawn/errors.rb +94 -0
  176. data/lib/prawn/font.rb +341 -0
  177. data/lib/prawn/font/afm.rb +225 -0
  178. data/lib/prawn/font/dfont.rb +42 -0
  179. data/lib/prawn/font/ttf.rb +350 -0
  180. data/lib/prawn/graphics.rb +325 -0
  181. data/lib/prawn/graphics/cap_style.rb +38 -0
  182. data/lib/prawn/graphics/color.rb +205 -0
  183. data/lib/prawn/graphics/dash.rb +71 -0
  184. data/lib/prawn/graphics/join_style.rb +38 -0
  185. data/lib/prawn/graphics/transformation.rb +156 -0
  186. data/lib/prawn/graphics/transparency.rb +99 -0
  187. data/lib/prawn/images.rb +348 -0
  188. data/lib/prawn/images/jpg.rb +46 -0
  189. data/lib/prawn/images/png.rb +226 -0
  190. data/lib/prawn/measurement_extensions.rb +46 -0
  191. data/lib/prawn/measurements.rb +71 -0
  192. data/lib/prawn/outline.rb +278 -0
  193. data/lib/prawn/repeater.rb +129 -0
  194. data/lib/prawn/security.rb +262 -0
  195. data/lib/prawn/security/arcfour.rb +51 -0
  196. data/lib/prawn/stamp.rb +126 -0
  197. data/lib/prawn/table.rb +421 -0
  198. data/lib/prawn/table/accessors.rb +180 -0
  199. data/lib/prawn/table/cell.rb +350 -0
  200. data/lib/prawn/table/cell/in_table.rb +27 -0
  201. data/lib/prawn/table/cell/subtable.rb +65 -0
  202. data/lib/prawn/table/cell/text.rb +125 -0
  203. data/lib/prawn/text.rb +449 -0
  204. data/lib/prawn/text/box.rb +392 -0
  205. data/lib/prawn/text/formatted.rb +4 -0
  206. data/lib/prawn/text/formatted/box.rb +228 -0
  207. data/lib/prawn/text/formatted/fragment.rb +181 -0
  208. data/lib/prawn/text/formatted/parser.rb +213 -0
  209. data/spec/annotations_spec.rb +90 -0
  210. data/spec/bounding_box_spec.rb +190 -0
  211. data/spec/cell_spec.rb +348 -0
  212. data/spec/destinations_spec.rb +15 -0
  213. data/spec/document_spec.rb +473 -0
  214. data/spec/font_spec.rb +324 -0
  215. data/spec/formatted_text_arranger_spec.rb +426 -0
  216. data/spec/formatted_text_box_spec.rb +756 -0
  217. data/spec/formatted_text_fragment_spec.rb +211 -0
  218. data/spec/graphics_spec.rb +446 -0
  219. data/spec/images_spec.rb +96 -0
  220. data/spec/inline_formatted_text_parser_spec.rb +502 -0
  221. data/spec/jpg_spec.rb +25 -0
  222. data/spec/line_wrap_spec.rb +341 -0
  223. data/spec/measurement_units_spec.rb +23 -0
  224. data/spec/name_tree_spec.rb +112 -0
  225. data/spec/object_store_spec.rb +160 -0
  226. data/spec/outline_spec.rb +269 -0
  227. data/spec/pdf_object_spec.rb +170 -0
  228. data/spec/png_spec.rb +237 -0
  229. data/spec/reference_spec.rb +82 -0
  230. data/spec/repeater_spec.rb +96 -0
  231. data/spec/security_spec.rb +120 -0
  232. data/spec/snapshot_spec.rb +138 -0
  233. data/spec/spec_helper.rb +26 -0
  234. data/spec/stamp_spec.rb +108 -0
  235. data/spec/stroke_styles_spec.rb +163 -0
  236. data/spec/table_spec.rb +598 -0
  237. data/spec/template_spec.rb +158 -0
  238. data/spec/text_at_spec.rb +119 -0
  239. data/spec/text_box_spec.rb +742 -0
  240. data/spec/text_spacing_spec.rb +75 -0
  241. data/spec/text_spec.rb +333 -0
  242. data/spec/text_with_inline_formatting_spec.rb +193 -0
  243. data/spec/transparency_spec.rb +89 -0
  244. metadata +331 -0
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "Prawn::ObjectStore" do
6
+ before(:each) do
7
+ @store = Prawn::Core::ObjectStore.new
8
+ end
9
+
10
+ it "should create required roots by default, including info passed to new" do
11
+ store = Prawn::Core::ObjectStore.new(:info => {:Test => 3})
12
+ store.size.should == 3 # 3 default roots
13
+ store.info.data[:Test].should == 3
14
+ store.pages.data[:Count].should == 0
15
+ store.root.data[:Pages].should == store.pages
16
+ end
17
+
18
+ it "should import objects from an existing PDF" do
19
+ filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
20
+ store = Prawn::Core::ObjectStore.new(:template => filename)
21
+ store.size.should == 5
22
+ end
23
+
24
+ it "should point to existing roots when importing objects from an existing PDF" do
25
+ filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
26
+ store = Prawn::Core::ObjectStore.new(:template => filename)
27
+ store.info.class.should == Prawn::Core::Reference
28
+ store.root.class.should == Prawn::Core::Reference
29
+ end
30
+
31
+ it "should initialize with pages when importing objects from an existing PDF" do
32
+ filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
33
+ store = Prawn::Core::ObjectStore.new(:template => filename)
34
+ store.pages.data[:Count].should == 1
35
+ end
36
+
37
+ it "should import all objects from a PDF that has an indirect reference in a stream dict" do
38
+ filename = "#{Prawn::BASEDIR}/data/pdfs/indirect_reference.pdf"
39
+ store = Prawn::Core::ObjectStore.new(:template => filename)
40
+ store.size.should == 8
41
+ end
42
+
43
+ it "should raise ArgumentError when given a file that doesn exist as a template" do
44
+ filename = "not_really_there.pdf"
45
+
46
+ lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(ArgumentError)
47
+ end
48
+
49
+ it "should raise Prawn::Errors::TemplateError when given a non PDF as a template" do
50
+ filename = "#{Prawn::BASEDIR}/data/images/dice.png"
51
+
52
+ lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(Prawn::Errors::TemplateError)
53
+ end
54
+
55
+ it "should raise Prawn::Errors::TemplateError when given an encrypted PDF as a template" do
56
+ filename = "#{Prawn::BASEDIR}/data/pdfs/encrypted.pdf"
57
+
58
+ lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(Prawn::Errors::TemplateError)
59
+ end
60
+
61
+ it "should add to its objects when ref() is called" do
62
+ count = @store.size
63
+ @store.ref("blah")
64
+ @store.size.should == count + 1
65
+ end
66
+
67
+ it "should accept push with a Prawn::Reference" do
68
+ r = Prawn::Core::Reference(123, "blah")
69
+ @store.push(r)
70
+ @store[r.identifier].should == r
71
+ end
72
+
73
+ it "should accept arbitrary data and use it to create a Prawn::Reference" do
74
+ @store.push(123, "blahblah")
75
+ @store[123].data.should == "blahblah"
76
+ end
77
+
78
+ it "should be Enumerable, yielding in order of submission" do
79
+ # higher IDs to bypass the default roots
80
+ [10, 11, 12].each do |id|
81
+ @store.push(id, "some data #{id}")
82
+ end
83
+ @store.map{|ref| ref.identifier}[-3..-1].should == [10, 11, 12]
84
+ end
85
+ end
86
+
87
+ describe "Prawn::ObjectStore#compact" do
88
+ it "should do nothing to an ObjectStore with all live refs" do
89
+ store = Prawn::Core::ObjectStore.new
90
+ store.info.data[:Blah] = store.ref(:some => "structure")
91
+ old_size = store.size
92
+ store.compact
93
+
94
+ store.size.should == old_size
95
+ end
96
+
97
+ it "should remove dead objects, renumbering live objects from 1" do
98
+ store = Prawn::Core::ObjectStore.new
99
+ store.ref(:some => "structure")
100
+ old_size = store.size
101
+ store.compact
102
+
103
+ store.size.should.be < old_size
104
+ store.map{ |o| o.identifier }.should == (1..store.size).to_a
105
+ end
106
+
107
+ it "should detect and remove dead objects that were once live" do
108
+ store = Prawn::Core::ObjectStore.new
109
+ store.info.data[:Blah] = store.ref(:some => "structure")
110
+ store.info.data[:Blah] = :overwritten
111
+ old_size = store.size
112
+ store.compact
113
+
114
+ store.size.should.be < old_size
115
+ store.map{ |o| o.identifier }.should == (1..store.size).to_a
116
+ end
117
+ end
118
+
119
+ describe "Prawn::ObjectStorie#object_id_for_page" do
120
+ it "should return the object ID of an imported template page" do
121
+ filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
122
+ store = Prawn::Core::ObjectStore.new(:template => filename)
123
+ store.object_id_for_page(0).should == 4
124
+ end
125
+
126
+ it "should return the object ID of the first imported template page" do
127
+ filename = "#{Prawn::BASEDIR}/data/pdfs/two_hexagons.pdf"
128
+ store = Prawn::Core::ObjectStore.new(:template => filename)
129
+ store.object_id_for_page(1).should == 4
130
+ end
131
+
132
+ it "should return the object ID of the last imported template page" do
133
+ filename = "#{Prawn::BASEDIR}/data/pdfs/two_hexagons.pdf"
134
+ store = Prawn::Core::ObjectStore.new(:template => filename)
135
+ store.object_id_for_page(-1).should == 6
136
+ end
137
+
138
+ it "should return the object ID of the first page of a template that uses nested Pages" do
139
+ filename = "#{Prawn::BASEDIR}/data/pdfs/nested_pages.pdf"
140
+ store = Prawn::Core::ObjectStore.new(:template => filename)
141
+ store.object_id_for_page(1).should == 5
142
+ end
143
+
144
+ it "should return the object ID of the last page of a template that uses nested Pages" do
145
+ filename = "#{Prawn::BASEDIR}/data/pdfs/nested_pages.pdf"
146
+ store = Prawn::Core::ObjectStore.new(:template => filename)
147
+ store.object_id_for_page(-1).should == 8
148
+ end
149
+
150
+ it "should return nil if given an invalid page number" do
151
+ filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
152
+ store = Prawn::Core::ObjectStore.new(:template => filename)
153
+ store.object_id_for_page(10).should == nil
154
+ end
155
+
156
+ it "should return nil if given an invalid page number" do
157
+ store = Prawn::Core::ObjectStore.new
158
+ store.object_id_for_page(10).should == nil
159
+ end
160
+ end
@@ -0,0 +1,269 @@
1
+ # encoding: utf-8
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
3
+
4
+ describe "Outline" do
5
+ before(:each) do
6
+ @pdf = Prawn::Document.new() do
7
+ text "Page 1. This is the first Chapter. "
8
+ start_new_page
9
+ text "Page 2. More in the first Chapter. "
10
+ start_new_page
11
+ define_outline do
12
+ section 'Chapter 1', :page => 1, :closed => true do
13
+ page 1, :title => 'Page 1'
14
+ page 2, :title => 'Page 2'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ if RUBY_VERSION >= "1.9"
20
+ describe "outline encoding" do
21
+ it "should store all outline titles as UTF-16" do
22
+ render_and_find_objects
23
+ @hash.values.each do |obj|
24
+ if obj.is_a?(Hash) && obj[:Title]
25
+ title = obj[:Title].dup
26
+ title.force_encoding("UTF-16LE")
27
+ title.valid_encoding?.should == true
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ describe "#generate_outline" do
34
+ before(:each) do
35
+ render_and_find_objects
36
+ end
37
+
38
+ it "should create a root outline dictionary item" do
39
+ assert_not_nil @outline_root
40
+ end
41
+
42
+ it "should set the first and last top items of the root outline dictionary item" do
43
+ referenced_object(@outline_root[:First]).should == @section_1
44
+ referenced_object(@outline_root[:Last]).should == @section_1
45
+ end
46
+
47
+ describe "#create_outline_item" do
48
+ it "should create outline items for each section and page" do
49
+ [@section_1, @page_1, @page_2].each {|item| assert_not_nil item}
50
+ end
51
+ end
52
+
53
+ describe "#set_relations, #set_variables_for_block, and #reset_parent" do
54
+ it "should link sibling items" do
55
+ referenced_object(@page_1[:Next]).should == @page_2
56
+ referenced_object(@page_2[:Prev]).should == @page_1
57
+ end
58
+
59
+ it "should link child items to parent item" do
60
+ [@page_1, @page_2].each {|page| referenced_object(page[:Parent]).should == @section_1 }
61
+ end
62
+
63
+ it "should set the first and last child items for parent item" do
64
+ referenced_object(@section_1[:First]).should == @page_1
65
+ referenced_object(@section_1[:Last]).should == @page_2
66
+ end
67
+ end
68
+
69
+ describe "#increase_count" do
70
+
71
+ it "should add the count of all descendant items" do
72
+ @outline_root[:Count].should == 3
73
+ @section_1[:Count].should.abs == 2
74
+ @page_1[:Count].should == 0
75
+ @page_2[:Count].should == 0
76
+ end
77
+
78
+ end
79
+
80
+ describe "closed option" do
81
+
82
+ it "should set the item's integer count to negative" do
83
+ @section_1[:Count].should == -2
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ describe "#outline.add_section" do
91
+ before(:each) do
92
+ @pdf.start_new_page
93
+ @pdf.text "Page 3. An added section "
94
+ @pdf.outline.add_section do
95
+ section 'Added Section', :page => 3 do
96
+ page 3, :title => 'Page 3'
97
+ end
98
+ end
99
+ render_and_find_objects
100
+ end
101
+
102
+ it "should add new outline items to document" do
103
+ [@section_2, @page_3].each { |item| assert_not_nil item}
104
+ end
105
+
106
+ it "should reset the last items for root outline dictionary" do
107
+ referenced_object(@outline_root[:First]).should == @section_1
108
+ referenced_object(@outline_root[:Last]).should == @section_2
109
+ end
110
+
111
+ it "should reset the next relation for the previous last top level item" do
112
+ referenced_object(@section_1[:Next]).should == @section_2
113
+ end
114
+
115
+ it "should set the previous relation of the addded to section" do
116
+ referenced_object(@section_2[:Prev]).should == @section_1
117
+ end
118
+
119
+ it "should increase the count of root outline dictionary" do
120
+ @outline_root[:Count].should == 5
121
+ end
122
+
123
+ end
124
+
125
+ describe "#outline.insert_section_after" do
126
+ describe "inserting in the middle of another section" do
127
+ before(:each) do
128
+ @pdf.go_to_page 1
129
+ @pdf.start_new_page
130
+ @pdf.text "Inserted Page"
131
+ @pdf.outline.insert_section_after 'Page 1' do
132
+ page page_number, :title => "Inserted Page"
133
+ end
134
+ render_and_find_objects
135
+ end
136
+
137
+ it "should insert new outline items to document" do
138
+ assert_not_nil @inserted_page
139
+ end
140
+
141
+ it "should adjust the count of all ancestors" do
142
+ @outline_root[:Count].should == 4
143
+ @section_1[:Count].should.abs == 3
144
+ end
145
+
146
+ describe "#adjust_relations" do
147
+
148
+ it "should reset the sibling relations of adjoining items to inserted item" do
149
+ referenced_object(@page_1[:Next]).should == @inserted_page
150
+ referenced_object(@page_2[:Prev]).should == @inserted_page
151
+ end
152
+
153
+ it "should set the sibling relation of added item to adjoining items" do
154
+ referenced_object(@inserted_page[:Next]).should == @page_2
155
+ referenced_object(@inserted_page[:Prev]).should == @page_1
156
+ end
157
+
158
+ it "should not affect the first and last relations of parent item" do
159
+ referenced_object(@section_1[:First]).should == @page_1
160
+ referenced_object(@section_1[:Last]).should == @page_2
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+
167
+ describe "inserting at the end of another section" do
168
+ before(:each) do
169
+ @pdf.go_to_page 2
170
+ @pdf.start_new_page
171
+ @pdf.text "Inserted Page"
172
+ @pdf.outline.insert_section_after 'Page 2' do
173
+ page page_number, :title => "Inserted Page"
174
+ end
175
+ render_and_find_objects
176
+ end
177
+
178
+ describe "#adjust_relations" do
179
+
180
+ it "should reset the sibling relations of adjoining item to inserted item" do
181
+ referenced_object(@page_2[:Next]).should == @inserted_page
182
+ end
183
+
184
+ it "should set the sibling relation of added item to adjoining items" do
185
+ assert_nil referenced_object(@inserted_page[:Next])
186
+ referenced_object(@inserted_page[:Prev]).should == @page_2
187
+ end
188
+
189
+ it "should adjust the last relation of parent item" do
190
+ referenced_object(@section_1[:Last]).should == @inserted_page
191
+ end
192
+
193
+ end
194
+ end
195
+
196
+ it "should require an existing title" do
197
+ assert_raise Prawn::Errors::UnknownOutlineTitle do
198
+ @pdf.go_to_page 1
199
+ @pdf.start_new_page
200
+ @pdf.text "Inserted Page"
201
+ @pdf.outline.insert_section_after 'Wrong page' do
202
+ page page_number, :title => "Inserted Page"
203
+ end
204
+ render_and_find_objects
205
+ end
206
+ end
207
+
208
+ end
209
+
210
+ describe "#page" do
211
+ it "should require a title option to be set" do
212
+ assert_raise Prawn::Errors::RequiredOption do
213
+ @pdf = Prawn::Document.new() do
214
+ text "Page 1. This is the first Chapter. "
215
+ define_outline do
216
+ page 1, :title => nil
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ context "foreign character encoding" do
225
+ before(:each) do
226
+ pdf = Prawn::Document.new() do
227
+ define_outline do
228
+ section 'La pomme croquée', :page => 1, :closed => true
229
+ end
230
+ end
231
+ @hash = PDF::Hash.new(StringIO.new(pdf.render, 'r+'))
232
+ end
233
+
234
+ it "should handle other encodings for the title" do
235
+ object = find_by_title('La pomme croquée')
236
+ object.should.not == nil
237
+ end
238
+ end
239
+
240
+ def render_and_find_objects
241
+ output = StringIO.new(@pdf.render, 'r+')
242
+ @hash = PDF::Hash.new(output)
243
+ @outline_root = @hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Outlines}
244
+ @pages = @hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
245
+ @section_1 = find_by_title('Chapter 1')
246
+ @page_1 = find_by_title('Page 1')
247
+ @page_2 = find_by_title('Page 2')
248
+ @section_2 = find_by_title('Added Section')
249
+ @page_3 = find_by_title('Page 3')
250
+ @inserted_page = find_by_title('Inserted Page')
251
+ end
252
+
253
+ # Outline titles are stored as UTF-16. This method accepts a UTF-8 outline title
254
+ # and returns the PDF Object that contains an outline with that name
255
+ def find_by_title(title)
256
+ @hash.values.find {|obj|
257
+ if obj.is_a?(Hash) && obj[:Title]
258
+ title_codepoints = obj[:Title].unpack("n*")
259
+ title_codepoints.shift
260
+ utf8_title = title_codepoints.pack("U*")
261
+ utf8_title == title ? obj : nil
262
+ end
263
+ }
264
+ end
265
+
266
+ def referenced_object(reference)
267
+ @hash[reference]
268
+ end
269
+
@@ -0,0 +1,170 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ # See PDF Reference, Sixth Edition (1.7) pp51-60 for details
6
+ describe "PDF Object Serialization" do
7
+
8
+ it "should convert Ruby's nil to PDF null" do
9
+ Prawn::Core::PdfObject(nil).should == "null"
10
+ end
11
+
12
+ it "should convert Ruby booleans to PDF booleans" do
13
+ Prawn::Core::PdfObject(true).should == "true"
14
+ Prawn::Core::PdfObject(false).should == "false"
15
+ end
16
+
17
+ it "should convert a Ruby number to PDF number" do
18
+ Prawn::Core::PdfObject(1).should == "1"
19
+ Prawn::Core::PdfObject(1.214112421).should == "1.214112421"
20
+ end
21
+
22
+ it "should convert a Ruby time object to a PDF timestamp" do
23
+ t = Time.now
24
+ Prawn::Core::PdfObject(t).should == t.strftime("(D:%Y%m%d%H%M%S%z").chop.chop + "'00')"
25
+ end
26
+
27
+ it "should convert a Ruby string to PDF string when inside a content stream" do
28
+ s = "I can has a string"
29
+ PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
30
+ end
31
+
32
+ it "should convert a Ruby string to a UTF-16 PDF string when outside a content stream" do
33
+ s = "I can has a string"
34
+ s_utf16 = "\xFE\xFF" + s.unpack("U*").pack("n*")
35
+ PDF::Inspector.parse(Prawn::Core::PdfObject(s, false)).should == s_utf16
36
+ end
37
+
38
+ it "should convert a Ruby string with characters outside the BMP to its " +
39
+ "UTF-16 representation with a BOM" do
40
+ # U+10192 ROMAN SEMUNCIA SIGN
41
+ semuncia = [65938].pack("U")
42
+ Prawn::Core::PdfObject(semuncia, false).upcase.should == "<FEFFD800DD92>"
43
+ end
44
+
45
+ it "should pass through bytes regardless of content stream status for ByteString" do
46
+ Prawn::Core::PdfObject(Prawn::Core::ByteString.new("\xDE\xAD\xBE\xEF")).upcase.
47
+ should == "<DEADBEEF>"
48
+ end
49
+
50
+ it "should escape parens when converting from Ruby string to PDF" do
51
+ s = 'I )(can has a string'
52
+ PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
53
+ end
54
+
55
+ it "should handle ruby escaped parens when converting to PDF string" do
56
+ s = 'I can \\)( has string'
57
+ PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
58
+ end
59
+
60
+ it "should escape various strings correctly when converting a LiteralString" do
61
+ ls = Prawn::Core::LiteralString.new("abc")
62
+ Prawn::Core::PdfObject(ls).should == "(abc)"
63
+
64
+ ls = Prawn::Core::LiteralString.new("abc\x0Ade") # should escape \n
65
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Ade)"
66
+
67
+ ls = Prawn::Core::LiteralString.new("abc\x0Dde") # should escape \r
68
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Dde)"
69
+
70
+ ls = Prawn::Core::LiteralString.new("abc\x09de") # should escape \t
71
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x09de)"
72
+
73
+ ls = Prawn::Core::LiteralString.new("abc\x08de") # should escape \b
74
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x08de)"
75
+
76
+ ls = Prawn::Core::LiteralString.new("abc\x0Cde") # should escape \f
77
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Cde)"
78
+
79
+ ls = Prawn::Core::LiteralString.new("abc(de") # should escape \(
80
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C(de)"
81
+
82
+ ls = Prawn::Core::LiteralString.new("abc)de") # should escape \)
83
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C)de)"
84
+
85
+ ls = Prawn::Core::LiteralString.new("abc\x5Cde") # should escape \\
86
+ Prawn::Core::PdfObject(ls).should == "(abc\x5C\x5Cde)"
87
+ Prawn::Core::PdfObject(ls).size.should == 9
88
+ end
89
+
90
+ it "should escape strings correctly when converting a LiteralString that is not utf-8" do
91
+ data = "\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\xaf\xd0"
92
+ ls = Prawn::Core::LiteralString.new(data)
93
+ Prawn::Core::PdfObject(ls).should == "(\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\x5c\xaf\xd0)"
94
+ end
95
+
96
+ it "should convert a Ruby symbol to PDF name" do
97
+ Prawn::Core::PdfObject(:my_symbol).should == "/my_symbol"
98
+ Prawn::Core::PdfObject(:"A;Name_With-Various***Characters?").should ==
99
+ "/A;Name_With-Various***Characters?"
100
+ end
101
+
102
+ it "should convert a whitespace or delimiter containing Ruby symbol to a PDF name" do
103
+ Prawn::Core::PdfObject(:"my symbol").should == "/my#20symbol"
104
+ Prawn::Core::PdfObject(:"my#symbol").should == "/my#23symbol"
105
+ Prawn::Core::PdfObject(:"my/symbol").should == "/my#2Fsymbol"
106
+ Prawn::Core::PdfObject(:"my(symbol").should == "/my#28symbol"
107
+ Prawn::Core::PdfObject(:"my)symbol").should == "/my#29symbol"
108
+ Prawn::Core::PdfObject(:"my<symbol").should == "/my#3Csymbol"
109
+ Prawn::Core::PdfObject(:"my>symbol").should == "/my#3Esymbol"
110
+ end
111
+
112
+ it "should convert a Ruby array to PDF Array when inside a content stream" do
113
+ Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
114
+ PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], true)).should ==
115
+ [[1,2],:foo, "Bar"]
116
+ end
117
+
118
+ it "should convert a Ruby array to PDF Array when outside a content stream" do
119
+ bar = "\xFE\xFF" + "Bar".unpack("U*").pack("n*")
120
+ Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
121
+ PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], false)).should ==
122
+ [[1,2],:foo, bar]
123
+ end
124
+
125
+ it "should convert a Ruby hash to a PDF Dictionary when inside a content stream" do
126
+ dict = Prawn::Core::PdfObject( {:foo => :bar,
127
+ "baz" => [1,2,3],
128
+ :bang => {:a => "what", :b => [:you, :say] }}, true )
129
+
130
+ res = PDF::Inspector.parse(dict)
131
+
132
+ res[:foo].should == :bar
133
+ res[:baz].should == [1,2,3]
134
+ res[:bang].should == { :a => "what", :b => [:you, :say] }
135
+
136
+ end
137
+
138
+ it "should convert a Ruby hash to a PDF Dictionary when outside a content stream" do
139
+ what = "\xFE\xFF" + "what".unpack("U*").pack("n*")
140
+ dict = Prawn::Core::PdfObject( {:foo => :bar,
141
+ "baz" => [1,2,3],
142
+ :bang => {:a => "what", :b => [:you, :say] }}, false )
143
+
144
+ res = PDF::Inspector.parse(dict)
145
+
146
+ res[:foo].should == :bar
147
+ res[:baz].should == [1,2,3]
148
+ res[:bang].should == { :a => what, :b => [:you, :say] }
149
+
150
+ end
151
+
152
+ it "should not allow keys other than strings or symbols for PDF dicts" do
153
+ lambda { Prawn::Core::PdfObject(:foo => :bar, :baz => :bang, 1 => 4) }.
154
+ should.raise(Prawn::Errors::FailedObjectConversion)
155
+ end
156
+
157
+ it "should convert a Prawn::Reference to a PDF indirect object reference" do
158
+ ref = Prawn::Core::Reference(1,true)
159
+ Prawn::Core::PdfObject(ref).should == ref.to_s
160
+ end
161
+
162
+ it "should convert a NameTree::Node to a PDF hash" do
163
+ node = Prawn::Core::NameTree::Node.new(Prawn::Document.new, 10)
164
+ node.add "hello", 1.0
165
+ node.add "world", 2.0
166
+ data = Prawn::Core::PdfObject(node)
167
+ res = PDF::Inspector.parse(data)
168
+ res.should == {:Names => ["hello", 1.0, "world", 2.0]}
169
+ end
170
+ end