prawn-svg 0.21.0 → 0.22.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/README.md +11 -4
  4. data/lib/prawn-svg.rb +9 -6
  5. data/lib/prawn/svg/attributes.rb +6 -0
  6. data/lib/prawn/svg/attributes/clip_path.rb +17 -0
  7. data/lib/prawn/svg/attributes/display.rb +5 -0
  8. data/lib/prawn/svg/attributes/font.rb +38 -0
  9. data/lib/prawn/svg/attributes/opacity.rb +15 -0
  10. data/lib/prawn/svg/attributes/stroke.rb +35 -0
  11. data/lib/prawn/svg/attributes/transform.rb +50 -0
  12. data/lib/prawn/svg/calculators/aspect_ratio.rb +1 -1
  13. data/lib/prawn/svg/calculators/document_sizing.rb +2 -2
  14. data/lib/prawn/svg/calculators/pixels.rb +1 -1
  15. data/lib/prawn/svg/color.rb +44 -14
  16. data/lib/prawn/svg/document.rb +6 -5
  17. data/lib/prawn/svg/elements.rb +33 -0
  18. data/lib/prawn/svg/elements/base.rb +228 -0
  19. data/lib/prawn/svg/elements/circle.rb +25 -0
  20. data/lib/prawn/svg/elements/container.rb +15 -0
  21. data/lib/prawn/svg/elements/ellipse.rb +23 -0
  22. data/lib/prawn/svg/elements/gradient.rb +117 -0
  23. data/lib/prawn/svg/elements/ignored.rb +5 -0
  24. data/lib/prawn/svg/elements/image.rb +85 -0
  25. data/lib/prawn/svg/elements/line.rb +16 -0
  26. data/lib/prawn/svg/elements/path.rb +405 -0
  27. data/lib/prawn/svg/elements/polygon.rb +17 -0
  28. data/lib/prawn/svg/elements/polyline.rb +22 -0
  29. data/lib/prawn/svg/elements/rect.rb +33 -0
  30. data/lib/prawn/svg/elements/root.rb +9 -0
  31. data/lib/prawn/svg/elements/style.rb +10 -0
  32. data/lib/prawn/svg/elements/text.rb +87 -0
  33. data/lib/prawn/svg/elements/use.rb +29 -0
  34. data/lib/prawn/svg/extension.rb +2 -2
  35. data/lib/prawn/svg/font.rb +3 -3
  36. data/lib/prawn/svg/interface.rb +12 -5
  37. data/lib/prawn/svg/url_loader.rb +1 -1
  38. data/lib/prawn/svg/version.rb +2 -2
  39. data/prawn-svg.gemspec +3 -3
  40. data/spec/integration_spec.rb +59 -2
  41. data/spec/prawn/svg/attributes/font_spec.rb +49 -0
  42. data/spec/prawn/svg/attributes/transform_spec.rb +56 -0
  43. data/spec/prawn/svg/calculators/aspect_ratio_spec.rb +2 -2
  44. data/spec/prawn/svg/calculators/document_sizing_spec.rb +3 -3
  45. data/spec/prawn/svg/color_spec.rb +36 -15
  46. data/spec/prawn/svg/document_spec.rb +4 -4
  47. data/spec/prawn/svg/elements/base_spec.rb +125 -0
  48. data/spec/prawn/svg/elements/gradient_spec.rb +61 -0
  49. data/spec/prawn/svg/elements/path_spec.rb +123 -0
  50. data/spec/prawn/svg/elements/style_spec.rb +23 -0
  51. data/spec/prawn/svg/{parser → elements}/text_spec.rb +7 -8
  52. data/spec/prawn/svg/font_spec.rb +12 -12
  53. data/spec/prawn/svg/interface_spec.rb +7 -7
  54. data/spec/prawn/svg/url_loader_spec.rb +2 -2
  55. data/spec/sample_svg/gradients.svg +40 -0
  56. data/spec/sample_svg/rect02.svg +8 -11
  57. data/spec/spec_helper.rb +1 -1
  58. metadata +46 -18
  59. data/lib/prawn/svg/element.rb +0 -304
  60. data/lib/prawn/svg/parser.rb +0 -268
  61. data/lib/prawn/svg/parser/image.rb +0 -81
  62. data/lib/prawn/svg/parser/path.rb +0 -392
  63. data/lib/prawn/svg/parser/text.rb +0 -80
  64. data/spec/prawn/svg/element_spec.rb +0 -127
  65. data/spec/prawn/svg/parser/path_spec.rb +0 -89
  66. data/spec/prawn/svg/parser_spec.rb +0 -55
@@ -1,9 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/../../../spec_helper'
2
2
 
3
- describe Prawn::Svg::Parser::Text do
4
- let(:document) { Prawn::Svg::Document.new(svg, [800, 600], {}) }
5
- let(:element) { Prawn::Svg::Element.new(document, document.root, [], {}) }
6
- let(:parser) { Prawn::Svg::Parser::Text.new }
3
+ describe Prawn::SVG::Elements::Text do
4
+ let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {}) }
5
+ let(:element) { Prawn::SVG::Elements::Text.new(document, document.root, [], {}) }
7
6
 
8
7
  describe "xml:space preserve" do
9
8
  let(:svg) { %(<text#{attributes}>some\n\t text</text>) }
@@ -12,7 +11,7 @@ describe Prawn::Svg::Parser::Text do
12
11
  let(:attributes) { ' xml:space="preserve"' }
13
12
 
14
13
  it "converts newlines and tabs to spaces, and preserves spaces" do
15
- parser.parse(element)
14
+ element.process
16
15
 
17
16
  expect(element.calls).to eq [
18
17
  ["draw_text", ["some text", {:style=>nil, :at=>[0.0, 150.0]}], []]
@@ -24,7 +23,7 @@ describe Prawn::Svg::Parser::Text do
24
23
  let(:attributes) { '' }
25
24
 
26
25
  it "strips space" do
27
- parser.parse(element)
26
+ element.process
28
27
 
29
28
  expect(element.calls).to eq [
30
29
  ["draw_text", ["some text", {:style=>nil, :at=>[0.0, 150.0]}], []]
@@ -37,7 +36,7 @@ describe Prawn::Svg::Parser::Text do
37
36
  let(:svg) { '<g text-anchor="middle" font-family="sans-serif" font-size="12"><text x="50" y="14">Text</text></g>' }
38
37
 
39
38
  it "should inherit text-anchor from parent element" do
40
- parser.parse(element)
39
+ element.process
41
40
  expect(element.state[:text_anchor]).to eq 'middle'
42
41
  end
43
42
  end
@@ -46,7 +45,7 @@ describe Prawn::Svg::Parser::Text do
46
45
  let(:svg) { '<text letter-spacing="5">spaced</text>' }
47
46
 
48
47
  it "calls character_spacing with the requested size" do
49
- parser.parse(element)
48
+ element.process
50
49
 
51
50
  expect(element.base_calls).to eq [
52
51
  ["end_path", [], [
@@ -1,31 +1,31 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
- describe Prawn::Svg::Font do
3
+ describe Prawn::SVG::Font do
4
4
  describe :load do
5
5
  it "matches a built in font" do
6
- Prawn::Svg::Font.load("blah, 'courier', nothing").name.should == 'Courier'
6
+ Prawn::SVG::Font.load("blah, 'courier', nothing").name.should == 'Courier'
7
7
  end
8
8
 
9
9
  it "matches a default font" do
10
- Prawn::Svg::Font.load("serif").name.should == 'Times-Roman'
11
- Prawn::Svg::Font.load("blah, serif").name.should == 'Times-Roman'
12
- Prawn::Svg::Font.load("blah, serif , test").name.should == 'Times-Roman'
10
+ Prawn::SVG::Font.load("serif").name.should == 'Times-Roman'
11
+ Prawn::SVG::Font.load("blah, serif").name.should == 'Times-Roman'
12
+ Prawn::SVG::Font.load("blah, serif , test").name.should == 'Times-Roman'
13
13
  end
14
14
 
15
- if Prawn::Svg::Font.installed_fonts["Verdana"]
15
+ if Prawn::SVG::Font.installed_fonts["Verdana"]
16
16
  it "matches a font installed on the system" do
17
- Prawn::Svg::Font.load("verdana, sans-serif").name.should == 'Verdana'
18
- Prawn::Svg::Font.load("VERDANA, sans-serif").name.should == 'Verdana'
19
- Prawn::Svg::Font.load("something, \"Times New Roman\", serif").name.should == "Times New Roman"
20
- Prawn::Svg::Font.load("something, Times New Roman, serif").name.should == "Times New Roman"
17
+ Prawn::SVG::Font.load("verdana, sans-serif").name.should == 'Verdana'
18
+ Prawn::SVG::Font.load("VERDANA, sans-serif").name.should == 'Verdana'
19
+ Prawn::SVG::Font.load("something, \"Times New Roman\", serif").name.should == "Times New Roman"
20
+ Prawn::SVG::Font.load("something, Times New Roman, serif").name.should == "Times New Roman"
21
21
  end
22
22
  else
23
23
  it "not running font test because we couldn't find Verdana installed on the system"
24
24
  end
25
25
 
26
26
  it "returns nil if it can't find any such font" do
27
- Prawn::Svg::Font.load("blah, thing").should be_nil
28
- Prawn::Svg::Font.load("").should be_nil
27
+ Prawn::SVG::Font.load("blah, thing").should be_nil
28
+ Prawn::SVG::Font.load("").should be_nil
29
29
  end
30
30
  end
31
31
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Prawn::Svg::Interface do
3
+ describe Prawn::SVG::Interface do
4
4
  let(:bounds) { double(width: 800, height: 600) }
5
5
  let(:prawn) { instance_double(Prawn::Document, font_families: {}, bounds: bounds, cursor: 600) }
6
6
  let(:svg) { '<svg width="250" height="100"></svg>' }
@@ -11,19 +11,19 @@ describe Prawn::Svg::Interface do
11
11
  allow(Prawn).to receive(:debug).and_return(true)
12
12
 
13
13
  expect {
14
- Prawn::Svg::Interface.new(svg, prawn, :invalid => "option")
14
+ Prawn::SVG::Interface.new(svg, prawn, :invalid => "option")
15
15
  }.to raise_error(Prawn::Errors::UnknownOption)
16
16
  end
17
17
 
18
18
  it "does nothing if an invalid option is given and debug is off" do
19
- Prawn::Svg::Interface.new(svg, prawn, :invalid => "option")
19
+ Prawn::SVG::Interface.new(svg, prawn, :invalid => "option")
20
20
  end
21
21
  end
22
22
  end
23
23
 
24
24
  describe "#draw" do
25
25
  context "when the sizing object indicates the sizes are invalid" do
26
- let(:interface) { Prawn::Svg::Interface.new('<svg width="0"></svg>', prawn, {}) }
26
+ let(:interface) { Prawn::SVG::Interface.new('<svg width="0"></svg>', prawn, {}) }
27
27
 
28
28
  it "doesn't draw anything and adds a warning" do
29
29
  interface.draw
@@ -36,7 +36,7 @@ describe Prawn::Svg::Interface do
36
36
  subject { interface.position }
37
37
 
38
38
  context "when options[:at] supplied" do
39
- let(:interface) { Prawn::Svg::Interface.new(svg, prawn, at: [1, 2], position: :left) }
39
+ let(:interface) { Prawn::SVG::Interface.new(svg, prawn, at: [1, 2], position: :left) }
40
40
 
41
41
  it "returns options[:at]" do
42
42
  expect(subject).to eq [1, 2]
@@ -44,7 +44,7 @@ describe Prawn::Svg::Interface do
44
44
  end
45
45
 
46
46
  context "when only a position is supplied" do
47
- let(:interface) { Prawn::Svg::Interface.new(svg, prawn, position: position) }
47
+ let(:interface) { Prawn::SVG::Interface.new(svg, prawn, position: position) }
48
48
 
49
49
  context "(:left)" do
50
50
  let(:position) { :left }
@@ -68,7 +68,7 @@ describe Prawn::Svg::Interface do
68
68
  end
69
69
 
70
70
  context "when a vposition is supplied" do
71
- let(:interface) { Prawn::Svg::Interface.new(svg, prawn, vposition: vposition) }
71
+ let(:interface) { Prawn::SVG::Interface.new(svg, prawn, vposition: vposition) }
72
72
 
73
73
  context "(:top)" do
74
74
  let(:vposition) { :top }
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Prawn::Svg::UrlLoader do
4
- let(:loader) { Prawn::Svg::UrlLoader.new(:enable_cache => true, :enable_web => true) }
3
+ describe Prawn::SVG::UrlLoader do
4
+ let(:loader) { Prawn::SVG::UrlLoader.new(:enable_cache => true, :enable_web => true) }
5
5
 
6
6
  describe "#initialize" do
7
7
  it "sets options" do
@@ -0,0 +1,40 @@
1
+ <svg width="240" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <style type="text/css"><![CDATA[
4
+ #rect1 { fill: url(#Gradient1); }
5
+ .stop1 { stop-color: red; }
6
+ .stop2 { stop-color: black; stop-opacity: 0; }
7
+ .stop3 { stop-color: blue; }
8
+ ]]></style>
9
+ <linearGradient id="Gradient1">
10
+ <stop class="stop1" offset="0%"/>
11
+ <stop class="stop2" offset="50%"/>
12
+ <stop class="stop3" offset="100%"/>
13
+ </linearGradient>
14
+ <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
15
+ <stop offset="25%" stop-color="red"/>
16
+ <stop offset="50%" stop-color="black" stop-opacity="0"/>
17
+ <stop offset="75%" stop-color="blue"/>
18
+ </linearGradient>
19
+ <linearGradient id="Gradient3" x1="0" x2="1" y1="0" y2="1">
20
+ <stop offset="0%" stop-color="red"/>
21
+ <stop offset="30%" stop-color="yellow"/>
22
+ <stop offset="60%" stop-color="orange"/>
23
+ <stop offset="100%" stop-color="blue"/>
24
+ </linearGradient>
25
+ <linearGradient id="userspace" gradientUnits="userSpaceOnUse" x1="160" y1="90" x2="220" y2="90">
26
+ <stop offset="0" stop-color="red"/>
27
+ <stop offset="1" stop-color="blue"/>
28
+ </linearGradient>
29
+ </defs>
30
+
31
+ <rect id="rect1" x="10" y="10" rx="15" ry="15" width="50" height="100" stroke="black"/>
32
+ <rect x="10" y="120" rx="15" ry="15" width="50" height="100" fill="url(#Gradient2)" stroke="black"/>
33
+ <circle cx="110" cy="40" r="30" stroke="black" fill="url(#Gradient3)"/>
34
+ <ellipse cx="110" cy="100" rx="30" ry="20" stroke="black" fill="url(#Gradient1)"/>
35
+ <line x1="65" y1="120" x2="200" y2="200" stroke="url(#Gradient3)" stroke-width="5"/>
36
+ <path d="M80,140l0,50l30,20l0-40z" stroke="url(#Gradient3)" fill="url(#Gradient1)" stroke-width="3"/>
37
+ <polygon points="150,30 170,80 190,55 200,10" fill="url(#Gradient1)"/>
38
+ <rect x="150" y="90" width="80" height="30" fill="url(#userspace)" stroke="black"/>
39
+ <polyline points="150,130 170,170 190,155 200,110" stroke="url(#Gradient1)" stroke-width="3" fill="none"/>
40
+ </svg>
@@ -1,16 +1,13 @@
1
1
  <?xml version="1.0" standalone="no"?>
2
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
- <svg width="12cm" height="4cm" viewBox="0 0 1200 400"
5
- xmlns="http://www.w3.org/2000/svg" version="1.1">
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="12cm" height="8cm" viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg" version="1.1">
6
4
  <desc>Example rect02 - rounded rectangles</desc>
7
- <!-- Show outline of canvas using 'rect' element -->
8
- <rect x="1" y="1" width="1198" height="398"
9
- fill="none" stroke="blue" stroke-width="2"/>
10
- <rect x="100" y="100" width="400" height="200" rx="50"
11
- fill="green" />
5
+
6
+ <rect x="1" y="1" width="1198" height="798" fill="none" stroke="blue" stroke-width="2"/>
7
+ <rect x="100" y="100" width="400" height="200" rx="50" fill="green" />
8
+ <rect x="100" y="500" width="400" height="200" rx="100" ry="10" fill="orange" />
9
+
12
10
  <g transform="translate(700 210) rotate(-30)">
13
- <rect x="0" y="0" width="400" height="200" rx="50"
14
- fill="none" stroke="purple" stroke-width="30" />
11
+ <rect x="0" y="0" width="400" height="200" rx="50" fill="none" stroke="purple" stroke-width="30" />
15
12
  </g>
16
13
  </svg>
data/spec/spec_helper.rb CHANGED
@@ -15,4 +15,4 @@ RSpec.configure do |config|
15
15
  end
16
16
  end
17
17
 
18
- Prawn::Svg::Font.load_external_fonts(Prawn::Document.new.font_families)
18
+ Prawn::SVG::Font.load_external_fonts(Prawn::Document.new.font_families)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn-svg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-24 00:00:00.000000000 Z
11
+ date: 2015-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prawn
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.8.4
19
+ version: 0.11.1
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '3'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.8.4
29
+ version: 0.11.1
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3'
@@ -82,38 +82,61 @@ extra_rdoc_files: []
82
82
  files:
83
83
  - ".gitignore"
84
84
  - ".rspec"
85
+ - ".travis.yml"
85
86
  - Gemfile
86
87
  - LICENSE
87
88
  - README.md
88
89
  - Rakefile
89
90
  - lib/prawn-svg.rb
91
+ - lib/prawn/svg/attributes.rb
92
+ - lib/prawn/svg/attributes/clip_path.rb
93
+ - lib/prawn/svg/attributes/display.rb
94
+ - lib/prawn/svg/attributes/font.rb
95
+ - lib/prawn/svg/attributes/opacity.rb
96
+ - lib/prawn/svg/attributes/stroke.rb
97
+ - lib/prawn/svg/attributes/transform.rb
90
98
  - lib/prawn/svg/calculators/aspect_ratio.rb
91
99
  - lib/prawn/svg/calculators/document_sizing.rb
92
100
  - lib/prawn/svg/calculators/pixels.rb
93
101
  - lib/prawn/svg/color.rb
94
102
  - lib/prawn/svg/document.rb
95
- - lib/prawn/svg/element.rb
103
+ - lib/prawn/svg/elements.rb
104
+ - lib/prawn/svg/elements/base.rb
105
+ - lib/prawn/svg/elements/circle.rb
106
+ - lib/prawn/svg/elements/container.rb
107
+ - lib/prawn/svg/elements/ellipse.rb
108
+ - lib/prawn/svg/elements/gradient.rb
109
+ - lib/prawn/svg/elements/ignored.rb
110
+ - lib/prawn/svg/elements/image.rb
111
+ - lib/prawn/svg/elements/line.rb
112
+ - lib/prawn/svg/elements/path.rb
113
+ - lib/prawn/svg/elements/polygon.rb
114
+ - lib/prawn/svg/elements/polyline.rb
115
+ - lib/prawn/svg/elements/rect.rb
116
+ - lib/prawn/svg/elements/root.rb
117
+ - lib/prawn/svg/elements/style.rb
118
+ - lib/prawn/svg/elements/text.rb
119
+ - lib/prawn/svg/elements/use.rb
96
120
  - lib/prawn/svg/extension.rb
97
121
  - lib/prawn/svg/font.rb
98
122
  - lib/prawn/svg/interface.rb
99
- - lib/prawn/svg/parser.rb
100
- - lib/prawn/svg/parser/image.rb
101
- - lib/prawn/svg/parser/path.rb
102
- - lib/prawn/svg/parser/text.rb
103
123
  - lib/prawn/svg/url_loader.rb
104
124
  - lib/prawn/svg/version.rb
105
125
  - prawn-svg.gemspec
106
126
  - spec/integration_spec.rb
127
+ - spec/prawn/svg/attributes/font_spec.rb
128
+ - spec/prawn/svg/attributes/transform_spec.rb
107
129
  - spec/prawn/svg/calculators/aspect_ratio_spec.rb
108
130
  - spec/prawn/svg/calculators/document_sizing_spec.rb
109
131
  - spec/prawn/svg/color_spec.rb
110
132
  - spec/prawn/svg/document_spec.rb
111
- - spec/prawn/svg/element_spec.rb
133
+ - spec/prawn/svg/elements/base_spec.rb
134
+ - spec/prawn/svg/elements/gradient_spec.rb
135
+ - spec/prawn/svg/elements/path_spec.rb
136
+ - spec/prawn/svg/elements/style_spec.rb
137
+ - spec/prawn/svg/elements/text_spec.rb
112
138
  - spec/prawn/svg/font_spec.rb
113
139
  - spec/prawn/svg/interface_spec.rb
114
- - spec/prawn/svg/parser/path_spec.rb
115
- - spec/prawn/svg/parser/text_spec.rb
116
- - spec/prawn/svg/parser_spec.rb
117
140
  - spec/prawn/svg/url_loader_spec.rb
118
141
  - spec/sample_images/mushroom-long.jpg
119
142
  - spec/sample_images/mushroom-wide.jpg
@@ -130,6 +153,7 @@ files:
130
153
  - spec/sample_svg/ellipse01.svg
131
154
  - spec/sample_svg/gistfile1.svg
132
155
  - spec/sample_svg/google_charts.svg
156
+ - spec/sample_svg/gradients.svg
133
157
  - spec/sample_svg/hidden_paths.svg
134
158
  - spec/sample_svg/highcharts.svg
135
159
  - spec/sample_svg/image01.svg
@@ -176,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
200
  requirements:
177
201
  - - ">="
178
202
  - !ruby/object:Gem::Version
179
- version: 1.9.3
203
+ version: 2.0.0
180
204
  required_rubygems_version: !ruby/object:Gem::Requirement
181
205
  requirements:
182
206
  - - ">="
@@ -190,16 +214,19 @@ specification_version: 4
190
214
  summary: SVG renderer for Prawn PDF library
191
215
  test_files:
192
216
  - spec/integration_spec.rb
217
+ - spec/prawn/svg/attributes/font_spec.rb
218
+ - spec/prawn/svg/attributes/transform_spec.rb
193
219
  - spec/prawn/svg/calculators/aspect_ratio_spec.rb
194
220
  - spec/prawn/svg/calculators/document_sizing_spec.rb
195
221
  - spec/prawn/svg/color_spec.rb
196
222
  - spec/prawn/svg/document_spec.rb
197
- - spec/prawn/svg/element_spec.rb
223
+ - spec/prawn/svg/elements/base_spec.rb
224
+ - spec/prawn/svg/elements/gradient_spec.rb
225
+ - spec/prawn/svg/elements/path_spec.rb
226
+ - spec/prawn/svg/elements/style_spec.rb
227
+ - spec/prawn/svg/elements/text_spec.rb
198
228
  - spec/prawn/svg/font_spec.rb
199
229
  - spec/prawn/svg/interface_spec.rb
200
- - spec/prawn/svg/parser/path_spec.rb
201
- - spec/prawn/svg/parser/text_spec.rb
202
- - spec/prawn/svg/parser_spec.rb
203
230
  - spec/prawn/svg/url_loader_spec.rb
204
231
  - spec/sample_images/mushroom-long.jpg
205
232
  - spec/sample_images/mushroom-wide.jpg
@@ -216,6 +243,7 @@ test_files:
216
243
  - spec/sample_svg/ellipse01.svg
217
244
  - spec/sample_svg/gistfile1.svg
218
245
  - spec/sample_svg/google_charts.svg
246
+ - spec/sample_svg/gradients.svg
219
247
  - spec/sample_svg/hidden_paths.svg
220
248
  - spec/sample_svg/highcharts.svg
221
249
  - spec/sample_svg/image01.svg
@@ -1,304 +0,0 @@
1
- class Prawn::Svg::Element
2
- attr_reader :document, :element, :parent_calls, :base_calls, :state, :attributes
3
- attr_accessor :calls
4
-
5
- def initialize(document, element, parent_calls, state)
6
- @document = document
7
- @element = element
8
- @parent_calls = parent_calls
9
- @state = state
10
- @base_calls = @calls = []
11
-
12
- combine_attributes_and_style_declarations
13
- apply_styles
14
-
15
- if id = @attributes["id"]
16
- document.elements_by_id[id] = self
17
- end
18
- end
19
-
20
- def name
21
- @name ||= element.name
22
- end
23
-
24
- def each_child_element
25
- element.elements.each do |e|
26
- yield self.class.new(@document, e, @calls, @state.dup)
27
- end
28
- end
29
-
30
- def warnings
31
- @document.warnings
32
- end
33
-
34
- def add_call(name, *arguments)
35
- @calls << [name.to_s, arguments, []]
36
- end
37
-
38
- def add_call_and_enter(name, *arguments)
39
- @calls << [name.to_s, arguments, []]
40
- @calls = @calls.last.last
41
- end
42
-
43
- def append_calls_to_parent
44
- @parent_calls.concat(@base_calls)
45
- end
46
-
47
- def add_calls_from_element(other)
48
- @calls.concat other.base_calls
49
- end
50
-
51
-
52
- protected
53
- def apply_styles
54
- parse_transform_attribute_and_call
55
- parse_opacity_attributes_and_call
56
- parse_clip_path_attribute_and_call
57
- draw_types = parse_fill_and_stroke_attributes_and_call
58
- parse_stroke_attributes_and_call
59
- parse_font_attributes_and_call
60
- parse_display_attribute
61
- apply_drawing_call(draw_types)
62
- end
63
-
64
- def apply_drawing_call(draw_types)
65
- if !@state[:disable_drawing] && !container?
66
- if draw_types.empty? || @state[:display] == "none"
67
- add_call_and_enter("end_path")
68
- else
69
- add_call_and_enter(draw_types.join("_and_"))
70
- end
71
- end
72
- end
73
-
74
- def container?
75
- Prawn::Svg::Parser::CONTAINER_TAGS.include?(name)
76
- end
77
-
78
- def parse_transform_attribute_and_call
79
- return unless transform = @attributes['transform']
80
-
81
- parse_css_method_calls(transform).each do |name, arguments|
82
- case name
83
- when 'translate'
84
- x, y = arguments
85
- add_call_and_enter name, @document.distance(x.to_f, :x), -@document.distance(y.to_f, :y)
86
-
87
- when 'rotate'
88
- r, x, y = arguments.collect {|a| a.to_f}
89
- case arguments.length
90
- when 1
91
- add_call_and_enter name, -r, :origin => [0, @document.y('0')]
92
- when 3
93
- add_call_and_enter name, -r, :origin => [@document.x(x), @document.y(y)]
94
- else
95
- @document.warnings << "transform 'rotate' must have either one or three arguments"
96
- end
97
-
98
- when 'scale'
99
- x_scale = arguments[0].to_f
100
- y_scale = (arguments[1] || x_scale).to_f
101
- add_call_and_enter "transformation_matrix", x_scale, 0, 0, y_scale, 0, 0
102
-
103
- when 'matrix'
104
- if arguments.length != 6
105
- @document.warnings << "transform 'matrix' must have six arguments"
106
- else
107
- a, b, c, d, e, f = arguments.collect {|argument| argument.to_f}
108
- add_call_and_enter "transformation_matrix", a, -b, -c, d, @document.distance(e, :x), -@document.distance(f, :y)
109
- end
110
- else
111
- @document.warnings << "Unknown transformation '#{name}'; ignoring"
112
- end
113
- end
114
- end
115
-
116
- def parse_opacity_attributes_and_call
117
- # We can't do nested opacities quite like the SVG requires, but this is close enough.
118
- fill_opacity = stroke_opacity = clamp(@attributes['opacity'].to_f, 0, 1) if @attributes['opacity']
119
- fill_opacity = clamp(@attributes['fill-opacity'].to_f, 0, 1) if @attributes['fill-opacity']
120
- stroke_opacity = clamp(@attributes['stroke-opacity'].to_f, 0, 1) if @attributes['stroke-opacity']
121
-
122
- if fill_opacity || stroke_opacity
123
- state[:fill_opacity] = (state[:fill_opacity] || 1) * (fill_opacity || 1)
124
- state[:stroke_opacity] = (state[:stroke_opacity] || 1) * (stroke_opacity || 1)
125
-
126
- add_call_and_enter 'transparent', state[:fill_opacity], state[:stroke_opacity]
127
- end
128
- end
129
-
130
- def parse_clip_path_attribute_and_call
131
- return unless clip_path = @attributes['clip-path']
132
-
133
- if (matches = clip_path.strip.match(/\Aurl\(#(.*)\)\z/)).nil?
134
- document.warnings << "Only clip-path attributes with the form 'url(#xxx)' are supported"
135
- elsif (clip_path_element = @document.elements_by_id[matches[1]]).nil?
136
- document.warnings << "clip-path ID '#{matches[1]}' not defined"
137
- elsif clip_path_element.element.name != "clipPath"
138
- document.warnings << "clip-path ID '#{matches[1]}' does not point to a clipPath tag"
139
- else
140
- add_call_and_enter 'save_graphics_state'
141
- add_calls_from_element clip_path_element
142
- add_call "clip"
143
- end
144
- end
145
-
146
- def parse_fill_and_stroke_attributes_and_call
147
- ["fill", "stroke"].select do |type|
148
- case keyword = attribute_value_as_keyword(type)
149
- when nil
150
- when 'inherit'
151
- when 'none'
152
- state[type.to_sym] = false
153
- else
154
- color_attribute = keyword == 'currentcolor' ? 'color' : type
155
- color = @attributes[color_attribute]
156
-
157
- begin
158
- hex = Prawn::Svg::Color.color_to_hex(color)
159
- state[type.to_sym] = true
160
- add_call "#{type}_color", hex || '000000'
161
- rescue Prawn::Svg::Color::UnresolvableURLWithNoFallbackError
162
- state[type.to_sym] = false
163
- end
164
- end
165
-
166
- state[type.to_sym]
167
- end
168
- end
169
-
170
- CAP_STYLE_TRANSLATIONS = {"butt" => :butt, "round" => :round, "square" => :projecting_square}
171
-
172
- def parse_stroke_attributes_and_call
173
- if width = @attributes['stroke-width']
174
- add_call('line_width', @document.distance(width))
175
- end
176
-
177
- if (linecap = attribute_value_as_keyword('stroke-linecap')) && linecap != 'inherit'
178
- add_call('cap_style', CAP_STYLE_TRANSLATIONS.fetch(linecap, :butt))
179
- end
180
-
181
- if dasharray = attribute_value_as_keyword('stroke-dasharray')
182
- case dasharray
183
- when 'inherit'
184
- # don't do anything
185
- when 'none'
186
- add_call('undash')
187
- else
188
- array = dasharray.split(Prawn::Svg::Parser::COMMA_WSP_REGEXP)
189
- array *= 2 if array.length % 2 == 1
190
- number_array = array.map {|value| @document.distance(value)}
191
-
192
- if number_array.any? {|number| number < 0}
193
- @document.warnings << "stroke-dasharray cannot have negative numbers; treating as 'none'"
194
- add_call('undash')
195
- elsif number_array.inject(0) {|a, b| a + b} == 0
196
- add_call('undash')
197
- else
198
- add_call('dash', number_array)
199
- end
200
- end
201
- end
202
- end
203
-
204
- def parse_font_attributes_and_call
205
- if size = @attributes['font-size']
206
- @state[:font_size] = size.to_f
207
- end
208
- if weight = @attributes['font-weight']
209
- font_updated = true
210
- @state[:font_weight] = Prawn::Svg::Font.weight_for_css_font_weight(weight)
211
- end
212
- if style = @attributes['font-style']
213
- font_updated = true
214
- @state[:font_style] = style == 'italic' ? :italic : nil
215
- end
216
- if (family = @attributes['font-family']) && family.strip != ""
217
- font_updated = true
218
- @state[:font_family] = family
219
- end
220
- if (anchor = @attributes['text-anchor'])
221
- @state[:text_anchor] = anchor
222
- end
223
-
224
- if @state[:font_family] && font_updated
225
- usable_font_families = [@state[:font_family], document.fallback_font_name]
226
-
227
- font_used = usable_font_families.compact.detect do |name|
228
- if font = Prawn::Svg::Font.load(name, @state[:font_weight], @state[:font_style])
229
- @state[:font_subfamily] = font.subfamily
230
- add_call_and_enter 'font', font.name, :style => @state[:font_subfamily]
231
- true
232
- end
233
- end
234
-
235
- if font_used.nil?
236
- @document.warnings << "Font family '#{@state[:font_family]}' style '#{@state[:font_style] || 'normal'}' is not a known font, and the fallback font could not be found."
237
- end
238
- end
239
- end
240
-
241
- def parse_display_attribute
242
- @state[:display] = @attributes['display'].strip if @attributes['display']
243
- end
244
-
245
- def parse_css_method_calls(string)
246
- string.scan(/\s*(\w+)\(([^)]+)\)\s*/).collect do |call|
247
- name, argument_string = call
248
- arguments = argument_string.strip.split(/\s*[,\s]\s*/)
249
- [name, arguments]
250
- end
251
- end
252
-
253
- def clamp(value, min_value, max_value)
254
- [[value, min_value].max, max_value].min
255
- end
256
-
257
- def combine_attributes_and_style_declarations
258
- if @document && @document.css_parser
259
- tag_style = @document.css_parser.find_by_selector(element.name)
260
- id_style = @document.css_parser.find_by_selector("##{element.attributes["id"]}") if element.attributes["id"]
261
-
262
- if classes = element.attributes["class"]
263
- class_styles = classes.strip.split(/\s+/).collect do |class_name|
264
- @document.css_parser.find_by_selector(".#{class_name}")
265
- end
266
- end
267
-
268
- element_style = element.attributes['style']
269
-
270
- style = [tag_style, class_styles, id_style, element_style].flatten.collect do |s|
271
- s.nil? || s.strip == "" ? "" : "#{s}#{";" unless s.match(/;\s*\z/)}"
272
- end.join
273
- else
274
- style = element.attributes['style'] || ""
275
- end
276
-
277
- @attributes = parse_css_declarations(style)
278
-
279
- element.attributes.each do |name, value|
280
- name = name.downcase
281
- @attributes[name] = value unless @attributes[name]
282
- end
283
- end
284
-
285
- def parse_css_declarations(declarations)
286
- # copied from css_parser
287
- declarations.gsub!(/(^[\s]*)|([\s]*$)/, '')
288
-
289
- output = {}
290
- declarations.split(/[\;$]+/m).each do |decs|
291
- if matches = decs.match(/\s*(.[^:]*)\s*\:\s*(.[^;]*)\s*(;|\Z)/i)
292
- property, value, _ = matches.captures
293
- output[property.downcase] = value
294
- end
295
- end
296
- output
297
- end
298
-
299
- def attribute_value_as_keyword(name)
300
- if value = @attributes[name]
301
- value.strip.downcase
302
- end
303
- end
304
- end