prawn-svg 0.27.1 → 0.31.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.
- checksums.yaml +5 -5
- data/.travis.yml +6 -4
- data/LICENSE +1 -1
- data/README.md +23 -9
- data/lib/prawn-svg.rb +7 -1
- data/lib/prawn/svg/attributes/opacity.rb +4 -4
- data/lib/prawn/svg/attributes/transform.rb +2 -44
- data/lib/prawn/svg/calculators/document_sizing.rb +2 -2
- data/lib/prawn/svg/{css.rb → css/font_family_parser.rb} +3 -4
- data/lib/prawn/svg/css/selector_parser.rb +174 -0
- data/lib/prawn/svg/css/stylesheets.rb +146 -0
- data/lib/prawn/svg/document.rb +3 -15
- data/lib/prawn/svg/elements.rb +4 -2
- data/lib/prawn/svg/elements/base.rb +26 -23
- data/lib/prawn/svg/elements/clip_path.rb +12 -0
- data/lib/prawn/svg/elements/container.rb +1 -3
- data/lib/prawn/svg/elements/gradient.rb +83 -25
- data/lib/prawn/svg/elements/image.rb +2 -2
- data/lib/prawn/svg/elements/path.rb +42 -29
- data/lib/prawn/svg/elements/root.rb +4 -1
- data/lib/prawn/svg/elements/text.rb +1 -1
- data/lib/prawn/svg/elements/text_component.rb +63 -14
- data/lib/prawn/svg/elements/use.rb +23 -7
- data/lib/prawn/svg/extensions/additional_gradient_transforms.rb +23 -0
- data/lib/prawn/svg/font_registry.rb +4 -3
- data/lib/prawn/svg/interface.rb +26 -2
- data/lib/prawn/svg/loaders/data.rb +1 -1
- data/lib/prawn/svg/loaders/file.rb +4 -2
- data/lib/prawn/svg/properties.rb +2 -0
- data/lib/prawn/svg/state.rb +6 -3
- data/lib/prawn/svg/transform_parser.rb +72 -0
- data/lib/prawn/svg/version.rb +1 -1
- data/prawn-svg.gemspec +3 -4
- data/spec/prawn/svg/attributes/opacity_spec.rb +85 -0
- data/spec/prawn/svg/attributes/transform_spec.rb +30 -35
- data/spec/prawn/svg/calculators/document_sizing_spec.rb +4 -4
- data/spec/prawn/svg/{css_spec.rb → css/font_family_parser_spec.rb} +3 -3
- data/spec/prawn/svg/css/selector_parser_spec.rb +33 -0
- data/spec/prawn/svg/css/stylesheets_spec.rb +142 -0
- data/spec/prawn/svg/document_spec.rb +0 -33
- data/spec/prawn/svg/elements/base_spec.rb +58 -2
- data/spec/prawn/svg/elements/gradient_spec.rb +79 -4
- data/spec/prawn/svg/elements/path_spec.rb +29 -17
- data/spec/prawn/svg/elements/text_spec.rb +74 -16
- data/spec/prawn/svg/font_registry_spec.rb +30 -0
- data/spec/prawn/svg/interface_spec.rb +33 -1
- data/spec/prawn/svg/loaders/data_spec.rb +8 -0
- data/spec/prawn/svg/transform_parser_spec.rb +94 -0
- data/spec/sample_output/{directory → .keep} +0 -0
- data/spec/sample_svg/double_opacity.svg +6 -0
- data/spec/sample_svg/gradient_transform.svg +19 -0
- data/spec/sample_svg/links.svg +18 -0
- data/spec/sample_svg/radgrad01-bounding.svg +26 -0
- data/spec/sample_svg/radgrad01.svg +26 -0
- data/spec/sample_svg/svg_fill.svg +5 -0
- data/spec/sample_svg/text-decoration.svg +4 -0
- data/spec/sample_svg/text_stroke.svg +41 -0
- data/spec/sample_svg/transform.svg +20 -0
- data/spec/sample_svg/use_disordered.svg +17 -0
- data/spec/sample_svg/warning-radioactive.svg +98 -0
- data/spec/spec_helper.rb +2 -2
- metadata +137 -15
data/prawn-svg.gemspec
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require File.expand_path('../lib/prawn/svg/version', __FILE__)
|
3
3
|
|
4
|
-
|
4
|
+
Gem::Specification.new do |gem|
|
5
5
|
gem.name = 'prawn-svg'
|
6
6
|
gem.version = Prawn::SVG::VERSION
|
7
7
|
gem.summary = "SVG renderer for Prawn PDF library"
|
8
8
|
gem.description = "This gem allows you to render SVG directly into a PDF using the 'prawn' gem. Since PDF is vector-based, you'll get nice scaled graphics if you use SVG instead of an image."
|
9
|
-
gem.has_rdoc = false
|
10
9
|
gem.author = "Roger Nesbitt"
|
11
10
|
gem.email = "roger@seriousorange.com"
|
12
11
|
gem.homepage = "http://github.com/mogest/prawn-svg"
|
@@ -21,7 +20,7 @@ spec = Gem::Specification.new do |gem|
|
|
21
20
|
gem.required_ruby_version = '>= 2.1.0'
|
22
21
|
|
23
22
|
gem.add_runtime_dependency "prawn", ">= 0.11.1", "< 3"
|
24
|
-
gem.add_runtime_dependency "css_parser", "~> 1.
|
23
|
+
gem.add_runtime_dependency "css_parser", "~> 1.6"
|
25
24
|
gem.add_development_dependency "rspec", "~> 3.0"
|
26
|
-
gem.add_development_dependency "rake", "~>
|
25
|
+
gem.add_development_dependency "rake", "~> 13.0"
|
27
26
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::SVG::Attributes::Opacity do
|
4
|
+
class OpacityTestElement
|
5
|
+
include Prawn::SVG::Attributes::Opacity
|
6
|
+
|
7
|
+
attr_accessor :properties, :state
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@properties = ::Prawn::SVG::Properties.new
|
11
|
+
@state = ::Prawn::SVG::State.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def clamp(value, min_value, max_value)
|
15
|
+
[[value, min_value].max, max_value].min
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:element) { OpacityTestElement.new }
|
20
|
+
|
21
|
+
describe "#parse_opacity_attributes_and_call" do
|
22
|
+
subject { element.parse_opacity_attributes_and_call }
|
23
|
+
|
24
|
+
context "with no opacity specified" do
|
25
|
+
it "does nothing" do
|
26
|
+
expect(element).not_to receive(:add_call_and_enter)
|
27
|
+
subject
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with opacity" do
|
32
|
+
it "sets fill and stroke opacity" do
|
33
|
+
element.properties.opacity = '0.4'
|
34
|
+
|
35
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.4)
|
36
|
+
subject
|
37
|
+
|
38
|
+
expect(element.state.fill_opacity).to eq 0.4
|
39
|
+
expect(element.state.stroke_opacity).to eq 0.4
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with just fill opacity" do
|
44
|
+
it "sets fill opacity and sets stroke opacity to 1" do
|
45
|
+
element.properties.fill_opacity = '0.4'
|
46
|
+
|
47
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 1)
|
48
|
+
subject
|
49
|
+
|
50
|
+
expect(element.state.fill_opacity).to eq 0.4
|
51
|
+
expect(element.state.stroke_opacity).to eq 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with an existing fill/stroke opacity" do
|
56
|
+
it "multiplies the new opacity by the old" do
|
57
|
+
element.state.fill_opacity = 0.5
|
58
|
+
element.state.stroke_opacity = 0.8
|
59
|
+
|
60
|
+
element.properties.fill_opacity = '0.4'
|
61
|
+
element.properties.stroke_opacity = '0.5'
|
62
|
+
|
63
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.4)
|
64
|
+
subject
|
65
|
+
|
66
|
+
expect(element.state.fill_opacity).to eq 0.2
|
67
|
+
expect(element.state.stroke_opacity).to eq 0.4
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with stroke, fill, and opacity all specified" do
|
72
|
+
it "choses the lower of them" do
|
73
|
+
element.properties.fill_opacity = '0.4'
|
74
|
+
element.properties.stroke_opacity = '0.6'
|
75
|
+
element.properties.opacity = '0.5'
|
76
|
+
|
77
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.5)
|
78
|
+
subject
|
79
|
+
|
80
|
+
expect(element.state.fill_opacity).to eq 0.4
|
81
|
+
expect(element.state.stroke_opacity).to eq 0.5
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -14,43 +14,38 @@ describe Prawn::SVG::Attributes::Transform do
|
|
14
14
|
|
15
15
|
let(:element) { TransformTestElement.new }
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
subject { element.send :parse_transform_attribute_and_call }
|
18
|
+
|
19
|
+
context "when a non-identity matrix is requested" do
|
20
|
+
let(:transform) { 'translate(-5.5)' }
|
21
|
+
|
22
|
+
it "passes the transform and executes the returned matrix" do
|
23
|
+
expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 2, 3, 4, 5, 6])
|
24
|
+
expect(element).to receive(:add_call_and_enter).with('transformation_matrix', 1, 2, 3, 4, 5, 6)
|
25
|
+
|
26
|
+
element.attributes['transform'] = transform
|
27
|
+
subject
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when an identity matrix is requested" do
|
32
|
+
let(:transform) { 'translate(0)' }
|
33
|
+
|
34
|
+
it "does not execute any commands" do
|
35
|
+
expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 0, 0, 1, 0, 0])
|
36
|
+
expect(element).not_to receive(:add_call_and_enter)
|
37
|
+
|
38
|
+
element.attributes['transform'] = transform
|
39
|
+
subject
|
29
40
|
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when transform is blank" do
|
44
|
+
it "does nothing" do
|
45
|
+
expect(element).not_to receive(:parse_transform_attribute)
|
46
|
+
expect(element).not_to receive(:add_call_and_enter)
|
30
47
|
|
31
|
-
|
32
|
-
it "handles a single angle argument" do
|
33
|
-
expect(element).to receive(:add_call_and_enter).with('rotate', -5.5, :origin => [0, 0])
|
34
|
-
expect(element).to receive(:y).with('0').and_return(0)
|
35
|
-
|
36
|
-
element.attributes['transform'] = 'rotate(5.5)'
|
37
|
-
subject
|
38
|
-
end
|
39
|
-
|
40
|
-
it "handles three arguments" do
|
41
|
-
expect(element).to receive(:add_call_and_enter).with('rotate', -5.5, :origin => [1.0, 2.0])
|
42
|
-
expect(element).to receive(:x).with(1.0).and_return(1.0)
|
43
|
-
expect(element).to receive(:y).with(2.0).and_return(2.0)
|
44
|
-
|
45
|
-
element.attributes['transform'] = 'rotate(5.5 1 2)'
|
46
|
-
subject
|
47
|
-
end
|
48
|
-
|
49
|
-
it "does nothing and warns if two arguments" do
|
50
|
-
expect(element).to receive(:warnings).and_return([])
|
51
|
-
element.attributes['transform'] = 'rotate(5.5 1)'
|
52
|
-
subject
|
53
|
-
end
|
48
|
+
subject
|
54
49
|
end
|
55
50
|
end
|
56
51
|
end
|
@@ -31,8 +31,8 @@ describe Prawn::SVG::Calculators::DocumentSizing do
|
|
31
31
|
describe "#calculate" do
|
32
32
|
it "calculates the document sizing measurements for a given set of inputs" do
|
33
33
|
sizing.calculate
|
34
|
-
expect(sizing.x_offset).to eq
|
35
|
-
expect(sizing.y_offset).to eq
|
34
|
+
expect(sizing.x_offset).to eq(-75 / 0.25)
|
35
|
+
expect(sizing.y_offset).to eq(-30)
|
36
36
|
expect(sizing.x_scale).to eq 0.25
|
37
37
|
expect(sizing.y_scale).to eq 0.25
|
38
38
|
expect(sizing.viewport_width).to eq 300
|
@@ -74,12 +74,12 @@ describe Prawn::SVG::Calculators::DocumentSizing do
|
|
74
74
|
context "when a viewBox is specified" do
|
75
75
|
let(:attributes) { {"viewBox" => "0 0 100 200"} }
|
76
76
|
|
77
|
-
it "defaults to 100% width and height" do
|
77
|
+
it "defaults to 100% width and uses the viewbox ratio for height" do
|
78
78
|
sizing.calculate
|
79
79
|
expect(sizing.viewport_width).to eq 100
|
80
80
|
expect(sizing.viewport_height).to eq 200
|
81
81
|
expect(sizing.output_width).to eq 1200
|
82
|
-
expect(sizing.output_height).to eq
|
82
|
+
expect(sizing.output_height).to eq 2400
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe Prawn::SVG::CSS do
|
4
|
-
describe "#
|
3
|
+
RSpec.describe Prawn::SVG::CSS::FontFamilyParser do
|
4
|
+
describe "#parse" do
|
5
5
|
it "correctly handles quotes and escaping" do
|
6
6
|
tests = {
|
7
7
|
"" => [],
|
@@ -17,7 +17,7 @@ RSpec.describe Prawn::SVG::CSS do
|
|
17
17
|
}
|
18
18
|
|
19
19
|
tests.each do |string, expected|
|
20
|
-
expect(Prawn::SVG::CSS.
|
20
|
+
expect(Prawn::SVG::CSS::FontFamilyParser.parse(string)).to eq expected
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Prawn::SVG::CSS::SelectorParser do
|
4
|
+
describe "::parse" do
|
5
|
+
it "parses a simple selector" do
|
6
|
+
expect(described_class.parse("div")).to eq [{name: "div"}]
|
7
|
+
expect(described_class.parse(".c1")).to eq [{class: ["c1"]}]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "parses a complex selector" do
|
11
|
+
result = described_class.parse("div#count .c1.c2 > span.large + div~.other:first-child *:nth-child(3)")
|
12
|
+
expect(result).to eq [
|
13
|
+
{name: "div", id: ["count"]},
|
14
|
+
{combinator: :descendant, class: ["c1", "c2"]},
|
15
|
+
{combinator: :child, name: "span", class: ["large"]},
|
16
|
+
{combinator: :adjacent, name: "div"},
|
17
|
+
{combinator: :siblings, class: ["other"], pseudo_class: ["first-child"]},
|
18
|
+
{combinator: :descendant, name: "*", pseudo_class: ["nth-child(3)"]},
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "parses attributes" do
|
23
|
+
expect(described_class.parse("[abc]")).to eq [{attribute: [["abc", nil, nil]]}]
|
24
|
+
expect(described_class.parse("[abc=123]")).to eq [{attribute: [["abc", '=', '123']]}]
|
25
|
+
expect(described_class.parse("[abc^=123]")).to eq [{attribute: [["abc", '^=', '123']]}]
|
26
|
+
expect(described_class.parse("[ abc ^= 123 ]")).to eq [{attribute: [["abc", '^=', '123']]}]
|
27
|
+
expect(described_class.parse("[abc^='123']")).to eq [{attribute: [["abc", '^=', '123']]}]
|
28
|
+
expect(described_class.parse("[abc^= '123' ]")).to eq [{attribute: [["abc", '^=', '123']]}]
|
29
|
+
expect(described_class.parse("[abc^= '123\\'456' ]")).to eq [{attribute: [["abc", '^=', '123\'456']]}]
|
30
|
+
expect(described_class.parse('[abc^= "123\\"456" ]')).to eq [{attribute: [["abc", '^=', '123"456']]}]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Prawn::SVG::CSS::Stylesheets do
|
4
|
+
describe "typical usage" do
|
5
|
+
let(:svg) { <<-SVG }
|
6
|
+
<svg>
|
7
|
+
<style>
|
8
|
+
#inner rect { fill: #0000ff; }
|
9
|
+
#outer { fill: #220000; }
|
10
|
+
.hero > rect { fill: #00ff00; }
|
11
|
+
rect { fill: #ff0000; }
|
12
|
+
rect ~ rect { fill: #330000; }
|
13
|
+
rect + rect { fill: #440000; }
|
14
|
+
rect:first-child:last-child { fill: #441234; }
|
15
|
+
|
16
|
+
circle:first-child { fill: #550000; }
|
17
|
+
circle:nth-child(2) { fill: #660000; }
|
18
|
+
circle:last-child { fill: #770000; }
|
19
|
+
|
20
|
+
square[chocolate] { fill: #880000; }
|
21
|
+
square[abc=def] { fill: #990000; }
|
22
|
+
square[abc^=ghi] { fill: #aa0000; }
|
23
|
+
square[abc$=jkl] { fill: #bb0000; }
|
24
|
+
square[abc*=mno] { fill: #cc0000; }
|
25
|
+
square[abc~=pqr] { fill: #dd0000; }
|
26
|
+
square[abc|=stu] { fill: #ee0000; }
|
27
|
+
</style>
|
28
|
+
|
29
|
+
<rect width="1" height="1" />
|
30
|
+
<rect width="2" height="2" id="outer" />
|
31
|
+
|
32
|
+
<g class="hero large">
|
33
|
+
<rect width="3" height="3" />
|
34
|
+
<rect width="4" height="4" style="fill: #777777;" />
|
35
|
+
<rect width="5" height="5" />
|
36
|
+
|
37
|
+
<g id="inner">
|
38
|
+
<rect width="6" height="6" />
|
39
|
+
</g>
|
40
|
+
|
41
|
+
<circle width="100" />
|
42
|
+
|
43
|
+
<g id="circles">
|
44
|
+
<circle width="7" />
|
45
|
+
<circle width="8" />
|
46
|
+
<circle width="9" />
|
47
|
+
</g>
|
48
|
+
</g>
|
49
|
+
|
50
|
+
<square width="10" chocolate="hi there" />
|
51
|
+
<square width="11" abc="def" />
|
52
|
+
<square width="12" abc="ghidef" />
|
53
|
+
<square width="13" abc="aghidefjkl" />
|
54
|
+
<square width="14" abc="agmnohidefjklx" />
|
55
|
+
<square width="15" abc="aeo cnj pqr" />
|
56
|
+
<square width="16" abc="eij-stu-asd" />
|
57
|
+
</svg>
|
58
|
+
SVG
|
59
|
+
|
60
|
+
it "associates styles with elements" do
|
61
|
+
result = Prawn::SVG::CSS::Stylesheets.new(CssParser::Parser.new, REXML::Document.new(svg)).load
|
62
|
+
width_and_styles = result.map { |k, v| [k.attributes["width"].to_i, v] }.sort_by(&:first)
|
63
|
+
|
64
|
+
expected = [
|
65
|
+
[1, [["fill", "#ff0000", false]]],
|
66
|
+
[2, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#220000", false]]],
|
67
|
+
[3, [["fill", "#ff0000", false], ["fill", "#00ff00", false]]],
|
68
|
+
[4, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]],
|
69
|
+
]
|
70
|
+
|
71
|
+
#
|
72
|
+
# Under ruby < 2.6, a bug in REXML causes the /following-sibling selector to
|
73
|
+
# only pick the first matching sibling. This means the + CSS combinator behaves
|
74
|
+
# incorrectly in the following example:
|
75
|
+
#
|
76
|
+
# <a>
|
77
|
+
# <b a="1" />
|
78
|
+
# <b a="2" />
|
79
|
+
# <b a="3" />
|
80
|
+
# </a>
|
81
|
+
#
|
82
|
+
# The css selector `a b + b` will only pick the second <b>, whereas it should
|
83
|
+
# pick both the second and third <b> elements.
|
84
|
+
#
|
85
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.6.0')
|
86
|
+
expected << [5, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#330000", false], ["fill", "#00ff00", false]]]
|
87
|
+
else
|
88
|
+
expected << [5, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]]
|
89
|
+
end
|
90
|
+
|
91
|
+
expected.concat [
|
92
|
+
[6, [["fill", "#ff0000", false], ["fill", "#441234", false], ["fill", "#0000ff", false]]],
|
93
|
+
[7, [["fill", "#550000", false]]],
|
94
|
+
[8, [["fill", "#660000", false]]],
|
95
|
+
[9, [["fill", "#770000", false]]],
|
96
|
+
[10, [["fill", "#880000", false]]],
|
97
|
+
[11, [["fill", "#990000", false]]],
|
98
|
+
[12, [["fill", "#aa0000", false]]],
|
99
|
+
[13, [["fill", "#bb0000", false]]],
|
100
|
+
[14, [["fill", "#cc0000", false]]],
|
101
|
+
[15, [["fill", "#dd0000", false]]],
|
102
|
+
[16, [["fill", "#ee0000", false]]],
|
103
|
+
]
|
104
|
+
|
105
|
+
expect(width_and_styles).to eq(expected)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "style tag parsing" do
|
110
|
+
let(:svg) do
|
111
|
+
<<-SVG
|
112
|
+
<svg>
|
113
|
+
<some-tag>
|
114
|
+
<style>a
|
115
|
+
before>
|
116
|
+
x <![CDATA[ y
|
117
|
+
inside <>>
|
118
|
+
k ]]> j
|
119
|
+
after
|
120
|
+
z</style>
|
121
|
+
</some-tag>
|
122
|
+
|
123
|
+
<other-tag>
|
124
|
+
<more-tag>
|
125
|
+
<style>hello</style>
|
126
|
+
</more-tag>
|
127
|
+
</other-tag>
|
128
|
+
</svg>
|
129
|
+
SVG
|
130
|
+
end
|
131
|
+
|
132
|
+
it "scans the document for style tags and adds the style information to the css parser" do
|
133
|
+
css_parser = instance_double(CssParser::Parser)
|
134
|
+
|
135
|
+
expect(css_parser).to receive(:add_block!).with("a\n before>\n x y\n inside <>>\n k j\n after\nz")
|
136
|
+
expect(css_parser).to receive(:add_block!).with("hello")
|
137
|
+
allow(css_parser).to receive(:each_rule_set)
|
138
|
+
|
139
|
+
Prawn::SVG::CSS::Stylesheets.new(css_parser, REXML::Document.new(svg)).load
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -25,37 +25,4 @@ describe Prawn::SVG::Document do
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
describe "#parse_style_elements" do
|
30
|
-
let(:svg) do
|
31
|
-
<<-SVG
|
32
|
-
<svg>
|
33
|
-
<some-tag>
|
34
|
-
<style>a
|
35
|
-
before>
|
36
|
-
x <![CDATA[ y
|
37
|
-
inside <>>
|
38
|
-
k ]]> j
|
39
|
-
after
|
40
|
-
z</style>
|
41
|
-
</some-tag>
|
42
|
-
|
43
|
-
<other-tag>
|
44
|
-
<more-tag>
|
45
|
-
<style>hello</style>
|
46
|
-
</more-tag>
|
47
|
-
</other-tag>
|
48
|
-
</svg>
|
49
|
-
SVG
|
50
|
-
end
|
51
|
-
|
52
|
-
it "scans the document for style tags and adds the style information to the css parser" do
|
53
|
-
css_parser = instance_double(CssParser::Parser)
|
54
|
-
|
55
|
-
expect(css_parser).to receive(:add_block!).with("a\n before>\n x y\n inside <>>\n k j\n after\nz")
|
56
|
-
expect(css_parser).to receive(:add_block!).with("hello")
|
57
|
-
|
58
|
-
Prawn::SVG::Document.new(svg, bounds, options, css_parser: css_parser)
|
59
|
-
end
|
60
|
-
end
|
61
28
|
end
|
@@ -25,14 +25,14 @@ describe Prawn::SVG::Elements::Base do
|
|
25
25
|
describe "applying calls from the standard attributes" do
|
26
26
|
let(:svg) do
|
27
27
|
<<-SVG
|
28
|
-
<something transform="
|
28
|
+
<something transform="scale(2)" fill-opacity="0.5" fill="red" stroke="blue" stroke-width="5"/>
|
29
29
|
SVG
|
30
30
|
end
|
31
31
|
|
32
32
|
it "appends the relevant calls" do
|
33
33
|
element.process
|
34
34
|
expect(element.base_calls).to eq [
|
35
|
-
["
|
35
|
+
["transformation_matrix", [2, 0, 0, 2, 0, 0], [
|
36
36
|
["transparent", [0.5, 1], [
|
37
37
|
["fill_color", ["ff0000"], []],
|
38
38
|
["stroke_color", ["0000ff"], []],
|
@@ -44,6 +44,36 @@ describe Prawn::SVG::Elements::Base do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
describe "fills and strokes" do
|
48
|
+
before { element.process }
|
49
|
+
subject { element.base_calls.last }
|
50
|
+
|
51
|
+
context "with neither fill nor stroke" do
|
52
|
+
let(:svg) { '<rect style="fill: none;"></rect>' }
|
53
|
+
it { is_expected.to eq ['end_path', [], []] }
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with a fill only" do
|
57
|
+
let(:svg) { '<rect style="fill: black;"></rect>' }
|
58
|
+
it { is_expected.to eq ['fill', [], []] }
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with a stroke only" do
|
62
|
+
let(:svg) { '<rect style="fill: none; stroke: black;"></rect>' }
|
63
|
+
it { is_expected.to eq ['stroke', [], []] }
|
64
|
+
end
|
65
|
+
|
66
|
+
context "with fill and stroke" do
|
67
|
+
let(:svg) { '<rect style="fill: black; stroke: black;"></rect>' }
|
68
|
+
it { is_expected.to eq ['fill_and_stroke', [], []] }
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with fill with evenodd fill rule" do
|
72
|
+
let(:svg) { '<rect style="fill: black; fill-rule: evenodd;"></rect>' }
|
73
|
+
it { is_expected.to eq ['fill', [{fill_rule: :even_odd}], []] }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
47
77
|
it "appends calls to the parent element" do
|
48
78
|
expect(element).to receive(:apply) do
|
49
79
|
element.send :add_call, "test", "argument"
|
@@ -131,4 +161,30 @@ describe Prawn::SVG::Elements::Base do
|
|
131
161
|
expect(element.computed_properties.fill).to eq 'none'
|
132
162
|
end
|
133
163
|
end
|
164
|
+
|
165
|
+
describe "stylesheets" do
|
166
|
+
let(:svg) { <<-SVG }
|
167
|
+
<svg>
|
168
|
+
<style>
|
169
|
+
.special rect { fill: green; }
|
170
|
+
rect { fill: red; }
|
171
|
+
</style>
|
172
|
+
<rect width="100" height="100"></rect>
|
173
|
+
<g class="special">
|
174
|
+
<rect width="100" height="100"></rect>
|
175
|
+
<rect width="100" height="100" style="fill: yellow;"></rect>
|
176
|
+
</g>
|
177
|
+
</svg>
|
178
|
+
SVG
|
179
|
+
|
180
|
+
it "applies stylesheet styling but style attributes take precedence" do
|
181
|
+
document = Prawn::SVG::Document.new(svg, [100, 100], {})
|
182
|
+
calls = []
|
183
|
+
element = Prawn::SVG::Elements::Root.new(document, document.root, calls)
|
184
|
+
element.process
|
185
|
+
|
186
|
+
fill_colors = calls.select { |cmd, _, _| cmd == 'fill_color' }.map { |_, args, _| args.first }
|
187
|
+
expect(fill_colors).to eq ['000000', 'ff0000', '008000', 'ffff00']
|
188
|
+
end
|
189
|
+
end
|
134
190
|
end
|