prawn-core 0.5.1 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/HACKING +46 -0
  2. data/README +9 -3
  3. data/Rakefile +7 -6
  4. data/examples/bounding_box/stretched_nesting.rb +67 -0
  5. data/examples/general/margin.rb +36 -0
  6. data/examples/general/multi_page_layout.rb +3 -1
  7. data/examples/general/page_numbering.rb +15 -0
  8. data/examples/general/stamp.rb +45 -0
  9. data/examples/graphics/stroke_cap_and_join.rb +45 -0
  10. data/examples/graphics/stroke_dash.rb +42 -0
  11. data/examples/graphics/transparency.rb +26 -0
  12. data/examples/text/text_box_returning_excess.rb +51 -0
  13. data/lib/prawn/byte_string.rb +7 -0
  14. data/lib/prawn/core.rb +7 -8
  15. data/lib/prawn/document/annotations.rb +3 -2
  16. data/lib/prawn/document/bounding_box.rb +15 -10
  17. data/lib/prawn/document/column_box.rb +1 -3
  18. data/lib/prawn/document/destinations.rb +11 -10
  19. data/lib/prawn/document/internals.rb +62 -19
  20. data/lib/prawn/document/snapshot.rb +71 -0
  21. data/lib/prawn/document/text/box.rb +7 -0
  22. data/lib/prawn/document/text/wrapping.rb +3 -0
  23. data/lib/prawn/document/text.rb +9 -2
  24. data/lib/prawn/document.rb +141 -25
  25. data/lib/prawn/errors.rb +12 -0
  26. data/lib/prawn/font/afm.rb +1 -1
  27. data/lib/prawn/font/ttf.rb +5 -5
  28. data/lib/prawn/font.rb +8 -5
  29. data/lib/prawn/graphics/cap_style.rb +35 -0
  30. data/lib/prawn/graphics/dash.rb +69 -0
  31. data/lib/prawn/graphics/join_style.rb +35 -0
  32. data/lib/prawn/graphics/transparency.rb +56 -0
  33. data/lib/prawn/graphics.rb +9 -1
  34. data/lib/prawn/images.rb +4 -4
  35. data/lib/prawn/name_tree.rb +2 -1
  36. data/lib/prawn/object_store.rb +63 -0
  37. data/lib/prawn/pdf_object.rb +4 -0
  38. data/lib/prawn/reference.rb +18 -5
  39. data/lib/prawn/stamp.rb +87 -0
  40. data/spec/bounding_box_spec.rb +9 -0
  41. data/spec/document_spec.rb +58 -5
  42. data/spec/images_spec.rb +1 -1
  43. data/spec/name_tree_spec.rb +14 -5
  44. data/spec/object_store_spec.rb +42 -0
  45. data/spec/pdf_object_spec.rb +5 -0
  46. data/spec/reference_spec.rb +40 -0
  47. data/spec/snapshot_spec.rb +115 -0
  48. data/spec/spec_helper.rb +1 -4
  49. data/spec/stamp_spec.rb +98 -0
  50. data/spec/stroke_styles_spec.rb +152 -0
  51. data/spec/text_box_spec.rb +26 -0
  52. data/spec/text_spec.rb +8 -1
  53. data/spec/transparency_spec.rb +61 -0
  54. data/vendor/pdf-inspector/lib/pdf/inspector/extgstate.rb +18 -0
  55. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +40 -1
  56. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +12 -3
  57. data/vendor/pdf-inspector/lib/pdf/inspector.rb +2 -1
  58. metadata +26 -2
data/spec/images_spec.rb CHANGED
@@ -24,7 +24,7 @@ describe "the image() function" do
24
24
  it "should return the image info object" do
25
25
  info = @pdf.image(@filename)
26
26
 
27
- assert info.kind_of?(Prawn::Images::JPG)
27
+ info.should.be.kind_of(Prawn::Images::JPG)
28
28
 
29
29
  info.height.should == 453
30
30
  end
@@ -19,7 +19,9 @@ def tree_value(name, value)
19
19
  end
20
20
 
21
21
  class RefExposingDocument < Prawn::Document
22
- attr_reader :objects
22
+ def object_store
23
+ @store
24
+ end
23
25
  end
24
26
 
25
27
  describe "Name Tree" do
@@ -43,20 +45,20 @@ describe "Name Tree" do
43
45
  end
44
46
 
45
47
  it "should create a two new references when root is split" do
46
- ref_count = @pdf.objects.length
48
+ ref_count = @pdf.object_store.length
47
49
  node = Prawn::NameTree::Node.new(@pdf, 3)
48
50
  tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
49
- @pdf.objects.length.should.equal ref_count+2
51
+ @pdf.object_store.length.should.equal ref_count+2
50
52
  end
51
53
 
52
54
  it "should create a one new reference when subtree is split" do
53
55
  node = Prawn::NameTree::Node.new(@pdf, 3)
54
56
  tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
55
57
 
56
- ref_count = @pdf.objects.length # save when root is split
58
+ ref_count = @pdf.object_store.length # save when root is split
57
59
  tree_add(node, ["five", 5], ["six", 6], ["seven", 7])
58
60
  tree_dump(node).should == "[[five=5,four=4,one=1],[seven=7,six=6],[three=3,two=2]]"
59
- @pdf.objects.length.should.equal ref_count+1
61
+ @pdf.object_store.length.should.equal ref_count+1
60
62
  end
61
63
 
62
64
  it "should keep tree balanced when subtree split cascades to root" do
@@ -66,6 +68,13 @@ describe "Name Tree" do
66
68
  tree_dump(node).should == "[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]"
67
69
  end
68
70
 
71
+ it "should maintain order of already properly ordered nodes" do
72
+ node = Prawn::NameTree::Node.new(@pdf, 3)
73
+ tree_add(node, ["eight", 8], ["five", 5], ["four", 4], ["one", 1])
74
+ tree_add(node, ['seven', 7], ['six', 6], ['three', 3], ['two', 2])
75
+ tree_dump(node).should == "[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]"
76
+ end
77
+
69
78
  it "should emit only :Names key with to_hash if root is only node" do
70
79
  node = Prawn::NameTree::Node.new(@pdf, 3)
71
80
  tree_add(node, ["one", 1], ["two", 2], ["three", 3])
@@ -0,0 +1,42 @@
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::ObjectStore.new
8
+ end
9
+
10
+ it "should create required roots by default, including info passed to new" do
11
+ store = Prawn::ObjectStore.new(: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 add to its objects when ref() is called" do
19
+ count = @store.size
20
+ @store.ref("blah")
21
+ @store.size.should == count + 1
22
+ end
23
+
24
+ it "should accept push with a Prawn::Reference" do
25
+ r = Prawn::Reference(123, "blah")
26
+ @store.push(r)
27
+ @store[r.identifier].should == r
28
+ end
29
+
30
+ it "should accept arbitrary data and use it to create a Prawn::Reference" do
31
+ @store.push(123, "blahblah")
32
+ @store[123].data.should == "blahblah"
33
+ end
34
+
35
+ it "should be Enumerable, yielding in order of submission" do
36
+ # higher IDs to bypass the default roots
37
+ [10, 11, 12].each do |id|
38
+ @store.push(id, "some data #{id}")
39
+ end
40
+ @store.map{|ref| ref.identifier}[-3..-1].should == [10, 11, 12]
41
+ end
42
+ end
@@ -34,6 +34,11 @@ describe "PDF Object Serialization" do
34
34
  s_utf16 = "\xFE\xFF" + s.unpack("U*").pack("n*")
35
35
  PDF::Inspector.parse(Prawn::PdfObject(s, false)).should == s_utf16
36
36
  end
37
+
38
+ it "should pass through bytes regardless of content stream status for ByteString" do
39
+ Prawn::PdfObject(Prawn::ByteString.new("\xDE\xAD\xBE\xEF")).upcase.
40
+ should == "<DEADBEEF>"
41
+ end
37
42
 
38
43
  it "should escape parens when converting from Ruby string to PDF" do
39
44
  s = 'I )(can has a string'
@@ -39,4 +39,44 @@ describe "A Reference object" do
39
39
  "compressed stream expected to be smaller than source but wasn't"
40
40
  cref.data[:Filter].should == :FlateDecode
41
41
  end
42
+
43
+ it "should copy the data and stream from another ref on #replace" do
44
+ from = Prawn::Reference(3, {:foo => 'bar'})
45
+ from << "has a stream too"
46
+
47
+ to = Prawn::Reference(4, {:foo => 'baz'})
48
+ to.replace from
49
+
50
+ # should preserve identifier but copy data and stream
51
+ to.identifier.should == 4
52
+ to.data.should == from.data
53
+ to.stream.should == from.stream
54
+ end
55
+
56
+ it "should copy a compressed stream from a compressed ref on #replace" do
57
+ from = Prawn::Reference(5, {:foo => 'bar'})
58
+ from << "has a stream too " * 20
59
+ from.compress_stream
60
+
61
+ to = Prawn::Reference(6, {:foo => 'baz'})
62
+ to.replace from
63
+
64
+ to.identifier.should == 6
65
+ to.data.should == from.data
66
+ to.stream.should == from.stream
67
+ to.compressed?.should == true
68
+ end
69
+
70
+ describe "generated via Prawn::Document" do
71
+ it "should return a proper reference on ref!" do
72
+ pdf = Prawn::Document.new
73
+ pdf.ref!({}).is_a?(Prawn::Reference).should == true
74
+ end
75
+
76
+ it "should return an identifier on ref" do
77
+ pdf = Prawn::Document.new
78
+ r = pdf.ref({})
79
+ r.is_a?(Integer).should == true
80
+ end
81
+ end
42
82
  end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "Prawn::Document#transaction" do
6
+
7
+ it "should properly commit if no error is raised" do
8
+ pdf = Prawn::Document.new do
9
+ transaction do
10
+ text "This is shown"
11
+ end
12
+ end
13
+ text = PDF::Inspector::Text.analyze(pdf.render)
14
+ text.strings.should == ["This is shown"]
15
+ end
16
+
17
+ it "should not display text if transaction is rolled back" do
18
+ pdf = Prawn::Document.new do
19
+ transaction do
20
+ text "This is not shown"
21
+ rollback
22
+ end
23
+ end
24
+ text = PDF::Inspector::Text.analyze(pdf.render)
25
+ text.strings.should == []
26
+ end
27
+
28
+ it "should return true/false value indicating success of the transaction" do
29
+ Prawn::Document.new do
30
+ success = transaction { }
31
+ success.should == true
32
+
33
+ success = transaction { rollback }
34
+ success.should == false
35
+ end
36
+ end
37
+
38
+ it "should support nested transactions" do
39
+ pdf = Prawn::Document.new do
40
+ transaction do
41
+ text "This is shown"
42
+ transaction do
43
+ text "and this is not"
44
+ rollback
45
+ end
46
+ text "and this is"
47
+ end
48
+ end
49
+ text = PDF::Inspector::Text.analyze(pdf.render)
50
+ text.strings.should == ["This is shown", "and this is"]
51
+ end
52
+
53
+ it "should allow rollback of multiple pages" do
54
+ pdf = Prawn::Document.new do
55
+ transaction do
56
+ 5.times { start_new_page }
57
+ text "way out there and will never be shown"
58
+ rollback
59
+ end
60
+ text "This is the real text, only one page"
61
+ end
62
+
63
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
64
+ pages.size.should == 1
65
+ end
66
+
67
+ # Because the Pages object, when restored, points to the snapshotted pages
68
+ # by identifier, we have to restore the snapshot into the same page objects,
69
+ # or else old pages will appear in the post-rollback document.
70
+ it "should restore the pages into the same objects" do
71
+ Prawn::Document.new do
72
+ old_page_object_id = current_page.identifier
73
+ old_page_content_id = page_content.identifier
74
+
75
+ transaction do
76
+ start_new_page
77
+ rollback
78
+ end
79
+
80
+ current_page.identifier.should == old_page_object_id
81
+ page_content.identifier.should == old_page_content_id
82
+ end
83
+
84
+
85
+ end
86
+
87
+
88
+ describe "with a stamp dictionary present" do
89
+
90
+ it "should properly commit if no error is raised" do
91
+ pdf = Prawn::Document.new do
92
+ create_stamp("test_stamp") { text "This is shown", :at => [0,0] }
93
+ transaction do
94
+ stamp("test_stamp")
95
+ end
96
+ end
97
+ pdf.render.should =~ /\/Stamp1 Do/
98
+ end
99
+
100
+ it "should properly rollback when #rollback is called" do
101
+ pdf = Prawn::Document.new do
102
+ create_stamp("test_stamp") { text "This is not shown", :at => [0,0] }
103
+
104
+ transaction do
105
+ stamp("test_stamp")
106
+ rollback
107
+ end
108
+ end
109
+ pdf.render.should.not =~ /\/Stamp1 Do/
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
data/spec/spec_helper.rb CHANGED
@@ -16,8 +16,5 @@ require "pdf/reader"
16
16
  require "pdf/inspector"
17
17
 
18
18
  def create_pdf(klass=Prawn::Document)
19
- @pdf = klass.new(:left_margin => 0,
20
- :right_margin => 0,
21
- :top_margin => 0,
22
- :bottom_margin => 0)
19
+ @pdf = klass.new(:margin => 0)
23
20
  end
@@ -0,0 +1,98 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
2
+
3
+ describe "Document with a stamp" do
4
+ it "should raise NameTaken error when attempt to create stamp "+
5
+ "with same name as an existing stamp" do
6
+ create_pdf
7
+ @pdf.create_stamp("MyStamp")
8
+ lambda {
9
+ @pdf.create_stamp("MyStamp")
10
+ }.should.raise(Prawn::Errors::NameTaken)
11
+ end
12
+
13
+ it "should raise InvalidName error when attempt to create "+
14
+ "stamp with a blank name" do
15
+ create_pdf
16
+ lambda {
17
+ @pdf.create_stamp("")
18
+ }.should.raise(Prawn::Errors::InvalidName)
19
+ end
20
+
21
+ it "a new XObject should be defined for each stamp created" do
22
+ create_pdf
23
+ @pdf.create_stamp("MyStamp")
24
+ @pdf.create_stamp("AnotherStamp")
25
+ @pdf.stamp("MyStamp")
26
+ @pdf.stamp("AnotherStamp")
27
+
28
+ inspector = PDF::Inspector::XObject.analyze(@pdf.render)
29
+ xobjects = inspector.page_xobjects.last
30
+ xobjects.length.should == 2
31
+ end
32
+
33
+ it "calling stamp with a name that does not match an existing stamp "+
34
+ "should raise UndefinedObjectName" do
35
+ create_pdf
36
+ @pdf.create_stamp("MyStamp")
37
+ lambda {
38
+ @pdf.stamp("OtherStamp")
39
+ }.should.raise(Prawn::Errors::UndefinedObjectName)
40
+ end
41
+
42
+ it "stamp should be drawn into the document each time stamp is called" do
43
+ create_pdf
44
+ @pdf.create_stamp("MyStamp")
45
+ @pdf.stamp("MyStamp")
46
+ @pdf.stamp("MyStamp")
47
+ @pdf.stamp("MyStamp")
48
+ # I had modified PDF::Inspector::XObject to receive the
49
+ # invoke_xobject message and count the number of times it was
50
+ # called, but it was only called once, so I reverted checking the
51
+ # output with a regular expression
52
+ @pdf.render.should =~ /(\/Stamp1 Do.*?){3}/m
53
+ end
54
+
55
+ it "resources added during stamp creation should be added to the "+
56
+ "stamp XObject, not the page" do
57
+ create_pdf
58
+ @pdf.create_stamp("MyStamp") do
59
+ @pdf.transparent(0.5) { @pdf.circle_at([100, 100], :radius => 10)}
60
+ end
61
+ @pdf.stamp("MyStamp")
62
+
63
+ # Inspector::XObject does not give information about resources, so
64
+ # resorting to string matching
65
+
66
+ output = @pdf.render
67
+ objects = output.split("endobj")
68
+ objects.each do |object|
69
+ if object =~ /\/Type \/Page$/
70
+ object.should.not =~ /\/ExtGState/
71
+ elsif object =~ /\/Type \/XObject$/
72
+ object.should =~ /\/ExtGState/
73
+ end
74
+ end
75
+ end
76
+
77
+ it "if ProcSet changes are made, they should be added to the Page "+
78
+ "object, not the stamp XObject" do
79
+ create_pdf
80
+ @pdf.create_stamp("MyStamp") do
81
+ @pdf.text("hello")
82
+ end
83
+ @pdf.stamp("MyStamp")
84
+
85
+ # Inspector::XObject does not give information about ProcSet, so
86
+ # resorting to string matching
87
+
88
+ output = @pdf.render
89
+ objects = output.split("endobj")
90
+ objects.each do |object|
91
+ if object =~ /\/Type \/Page$/
92
+ object.should =~ /\/ProcSet/
93
+ elsif object =~ /\/Type \/XObject$/
94
+ object.should.not =~ /\/ProcSet/
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "When stroking with default settings" do
6
+ before(:each) { create_pdf }
7
+ it "cap_style should be :butt" do
8
+ @pdf.cap_style.should == :butt
9
+ end
10
+
11
+ it "join_style should be :miter" do
12
+ @pdf.join_style.should == :miter
13
+ end
14
+
15
+ it "dashed? should be false" do
16
+ @pdf.should.not.be.dashed
17
+ end
18
+ end
19
+
20
+ describe "Cap styles" do
21
+ before(:each) { create_pdf }
22
+
23
+ it "should be able to use assignment operator" do
24
+ @pdf.cap_style = :round
25
+ @pdf.cap_style.should == :round
26
+ end
27
+
28
+ describe "#cap_style(:butt)" do
29
+ it "rendered PDF should include butt style cap" do
30
+ @pdf.cap_style(:butt)
31
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
32
+ cap_style.should == 0
33
+ end
34
+ end
35
+
36
+ describe "#cap_style(:round)" do
37
+ it "rendered PDF should include round style cap" do
38
+ @pdf.cap_style(:round)
39
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
40
+ cap_style.should == 1
41
+ end
42
+ end
43
+
44
+ describe "#cap_style(:projecting_square)" do
45
+ it "rendered PDF should include projecting_square style cap" do
46
+ @pdf.cap_style(:projecting_square)
47
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
48
+ cap_style.should == 2
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "Join styles" do
54
+ before(:each) { create_pdf }
55
+
56
+ it "should be able to use assignment operator" do
57
+ @pdf.join_style = :round
58
+ @pdf.join_style.should == :round
59
+ end
60
+
61
+ describe "#join_style(:miter)" do
62
+ it "rendered PDF should include miter style join" do
63
+ @pdf.join_style(:miter)
64
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
65
+ join_style.should == 0
66
+ end
67
+ end
68
+
69
+ describe "#join_style(:round)" do
70
+ it "rendered PDF should include round style join" do
71
+ @pdf.join_style(:round)
72
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
73
+ join_style.should == 1
74
+ end
75
+ end
76
+
77
+ describe "#join_style(:bevel)" do
78
+ it "rendered PDF should include bevel style join" do
79
+ @pdf.join_style(:bevel)
80
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
81
+ join_style.should == 2
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "Dashes" do
87
+ before(:each) { create_pdf }
88
+
89
+ it "should be able to use assignment operator" do
90
+ @pdf.dash = 2
91
+ @pdf.should.be.dashed
92
+ end
93
+
94
+ describe "setting a dash" do
95
+ it "dashed? should be true" do
96
+ @pdf.dash(2)
97
+ @pdf.should.be.dashed
98
+ end
99
+ it "rendered PDF should include a stroked dash" do
100
+ @pdf.dash(2)
101
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
102
+ dashes.stroke_dash.should == [[2, 2], 0]
103
+ end
104
+ end
105
+
106
+ describe "setting a dash by passing a single argument" do
107
+ it "space between dashes should be the same length as the dash in the rendered PDF" do
108
+ @pdf.dash(2)
109
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
110
+ dashes.stroke_dash.should == [[2, 2], 0]
111
+ end
112
+ end
113
+
114
+ describe "with a space option that differs from the first argument" do
115
+ it "space between dashes in the rendered PDF should be different length than the length of the dash" do
116
+ @pdf.dash(2, :space => 3)
117
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
118
+ dashes.stroke_dash.should == [[2, 3], 0]
119
+ end
120
+ end
121
+
122
+ describe "with a non-zero phase option" do
123
+ it "rendered PDF should include a non-zero phase" do
124
+ @pdf.dash(2, :phase => 1)
125
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
126
+ dashes.stroke_dash.should == [[2, 2], 1]
127
+ end
128
+ end
129
+
130
+ describe "clearing stroke dash" do
131
+ it "should restore solid line" do
132
+ @pdf.dash(2)
133
+ @pdf.undash
134
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
135
+ dashes.stroke_dash.should == [[], 0]
136
+ end
137
+ end
138
+
139
+ it "should reset the stroke dash on each new page if it has been defined" do
140
+ @pdf.start_new_page
141
+ @pdf.dash(2)
142
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
143
+ dashes.stroke_dash_count.should == 1
144
+
145
+ @pdf.start_new_page
146
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
147
+ dashes.stroke_dash_count.should == 2
148
+ dashes.stroke_dash.should == [[], 0]
149
+ @pdf.dash.should == { :dash => nil, :space => nil, :phase => 0 }
150
+ end
151
+
152
+ end
@@ -20,6 +20,32 @@ describe "A text box" do
20
20
  @box.text.should == "Oh hai\ntext box.\n" * 5
21
21
  end
22
22
 
23
+ it "render should return truncated text (NOTE: which may have had its whitespace mangled by wrap/unwrap)" do
24
+ @text = "Oh hai text box. " * 25
25
+ @overflow = :truncate
26
+ create_text_box
27
+ excess_text = @box.render
28
+ excess_text.should == "Oh hai text box. " * 20
29
+ end
30
+
31
+ it "render should attempt to preserve double newlines in excess text before returning it" do
32
+ line = "Oh hai text box. "
33
+ @text = line * 10 + "\n\n" + line * 10
34
+ @overflow = :truncate
35
+ create_text_box
36
+ excess_text = @box.render
37
+ excess_text.should == line * 5 + "\n\n" + line * 10
38
+ end
39
+
40
+ it "render should attempt to preserve single newlines in excess text before returning it" do
41
+ line = "Oh hai text box. "
42
+ @text = line * 10 + "\n" + line * 10
43
+ @overflow = :truncate
44
+ create_text_box
45
+ excess_text = @box.render
46
+ excess_text.should == line * 5 + "\n" + line * 10
47
+ end
48
+
23
49
  it "should have a height equal to @height" do
24
50
  @overflow = :truncate
25
51
  create_text_box
data/spec/text_spec.rb CHANGED
@@ -17,7 +17,8 @@ describe "when drawing text" do
17
17
  @pdf.y.should.be.close(position - 3*@pdf.font.height, 0.0001)
18
18
  end
19
19
 
20
- it "should advance down the document based on font ascender only if final_gap is given" do
20
+ it "should advance down the document based on font ascender only "+
21
+ "if final_gap is given" do
21
22
  position = @pdf.y
22
23
  @pdf.text "Foo", :final_gap => false
23
24
 
@@ -28,6 +29,12 @@ describe "when drawing text" do
28
29
  @pdf.y.should.be.close(position - 2*@pdf.font.height - @pdf.font.ascender, 0.0001)
29
30
  end
30
31
 
32
+ it "should not accept :align alongside :at" do
33
+ assert_raises(ArgumentError) do
34
+ @pdf.text "What could this mean?", :at => [100, 100], :align => :center
35
+ end
36
+ end
37
+
31
38
  it "should default to 12 point helvetica" do
32
39
  @pdf.text "Blah", :at => [100,100]
33
40
  text = PDF::Inspector::Text.analyze(@pdf.render)
@@ -0,0 +1,61 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
2
+
3
+ describe "Document with transparency" do
4
+ it "the PDF version should be at least 1.4" do
5
+ create_pdf
6
+ @pdf.transparent(0.5)
7
+ str = @pdf.render
8
+ str[0,8].should == "%PDF-1.4"
9
+ end
10
+
11
+ it "a new extended graphics state should be created for "+
12
+ "each unique transparency setting" do
13
+ create_pdf
14
+ @pdf.transparent(0.5, 0.2)
15
+ @pdf.transparent(0.5, 0.75)
16
+ extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates
17
+ extgstates.length.should == 2
18
+ end
19
+
20
+ it "a new extended graphics state should not be created for "+
21
+ "each duplicate transparency setting" do
22
+ create_pdf
23
+ @pdf.transparent(0.5, 0.75)
24
+ @pdf.transparent(0.5, 0.75)
25
+ extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates
26
+ extgstates.length.should == 1
27
+ end
28
+
29
+ it "setting the transparency with only one parameter sets the transparency"+
30
+ " for both the fill and the stroke" do
31
+ create_pdf
32
+ @pdf.transparent(0.5)
33
+ extgstate = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates[0]
34
+ extgstate[:opacity].should == 0.5
35
+ extgstate[:stroke_opacity].should == 0.5
36
+ end
37
+
38
+ it "setting the transparency with a numerical parameter and "+
39
+ "a :stroke should set the fill transparency to the numerical parameter "+
40
+ "and the stroke transparency to the option" do
41
+ create_pdf
42
+ @pdf.transparent(0.5, 0.2)
43
+ extgstate = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates[0]
44
+ extgstate[:opacity].should == 0.5
45
+ extgstate[:stroke_opacity].should == 0.2
46
+ end
47
+
48
+ describe "with more than one page" do
49
+ it "the extended graphic state resource should be added to both pages" do
50
+ create_pdf
51
+ @pdf.transparent(0.5, 0.2)
52
+ @pdf.start_new_page
53
+ @pdf.transparent(0.5, 0.2)
54
+ extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates
55
+ extgstate = extgstates[0]
56
+ extgstates.length.should == 2
57
+ extgstate[:opacity].should == 0.5
58
+ extgstate[:stroke_opacity].should == 0.2
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ module PDF
2
+ class Inspector
3
+ class ExtGState < Inspector
4
+ attr_accessor :extgstates
5
+
6
+ def initialize
7
+ @extgstates = []
8
+ end
9
+
10
+ def resource_extgstate(*params)
11
+ @extgstates << {
12
+ :opacity => params[1][:ca],
13
+ :stroke_opacity => params[1][:CA]
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end