prawn-svg 0.35.1 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -5
- data/README.md +4 -7
- data/lib/prawn/svg/attributes/opacity.rb +23 -8
- data/lib/prawn/svg/attributes/stroke.rb +7 -9
- data/lib/prawn/svg/attributes/transform.rb +1 -1
- data/lib/prawn/svg/calculators/pixels.rb +9 -22
- data/lib/prawn/svg/color.rb +58 -59
- data/lib/prawn/svg/css/font_parser.rb +46 -0
- data/lib/prawn/svg/document.rb +16 -9
- data/lib/prawn/svg/elements/base.rb +22 -30
- data/lib/prawn/svg/elements/gradient.rb +99 -74
- data/lib/prawn/svg/elements/line.rb +1 -1
- data/lib/prawn/svg/elements/marker.rb +2 -0
- data/lib/prawn/svg/elements/root.rb +1 -1
- data/lib/prawn/svg/elements/text_component.rb +3 -3
- data/lib/prawn/svg/funciri.rb +14 -0
- data/lib/prawn/svg/gradient_renderer.rb +313 -0
- data/lib/prawn/svg/length.rb +43 -0
- data/lib/prawn/svg/paint.rb +67 -0
- data/lib/prawn/svg/percentage.rb +24 -0
- data/lib/prawn/svg/properties.rb +208 -104
- data/lib/prawn/svg/renderer.rb +5 -0
- data/lib/prawn/svg/state.rb +5 -3
- data/lib/prawn/svg/transform_parser.rb +19 -13
- data/lib/prawn/svg/transform_utils.rb +37 -0
- data/lib/prawn/svg/version.rb +1 -1
- data/lib/prawn-svg.rb +7 -3
- data/prawn-svg.gemspec +4 -4
- data/spec/prawn/svg/attributes/opacity_spec.rb +27 -20
- data/spec/prawn/svg/attributes/transform_spec.rb +5 -2
- data/spec/prawn/svg/calculators/pixels_spec.rb +1 -2
- data/spec/prawn/svg/color_spec.rb +22 -52
- data/spec/prawn/svg/document_spec.rb +18 -4
- data/spec/prawn/svg/elements/base_spec.rb +9 -10
- data/spec/prawn/svg/elements/gradient_spec.rb +92 -36
- data/spec/prawn/svg/elements/marker_spec.rb +13 -15
- data/spec/prawn/svg/funciri_spec.rb +59 -0
- data/spec/prawn/svg/length_spec.rb +89 -0
- data/spec/prawn/svg/paint_spec.rb +96 -0
- data/spec/prawn/svg/pathable_spec.rb +3 -3
- data/spec/prawn/svg/pdfmatrix_spec.rb +60 -0
- data/spec/prawn/svg/percentage_spec.rb +60 -0
- data/spec/prawn/svg/properties_spec.rb +124 -107
- data/spec/prawn/svg/transform_parser_spec.rb +13 -13
- data/spec/sample_svg/gradient_stress_test.svg +115 -0
- metadata +17 -5
- data/lib/prawn/svg/extensions/additional_gradient_transforms.rb +0 -23
@@ -10,6 +10,10 @@ describe Prawn::SVG::Attributes::Opacity do
|
|
10
10
|
@properties = ::Prawn::SVG::Properties.new
|
11
11
|
@state = ::Prawn::SVG::State.new
|
12
12
|
end
|
13
|
+
|
14
|
+
def computed_properties
|
15
|
+
@state.computed_properties
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
let(:element) { OpacityTestElement.new }
|
@@ -26,55 +30,58 @@ describe Prawn::SVG::Attributes::Opacity do
|
|
26
30
|
|
27
31
|
context 'with opacity' do
|
28
32
|
it 'sets fill and stroke opacity' do
|
29
|
-
element.
|
33
|
+
element.computed_properties.opacity = '0.4'
|
30
34
|
|
31
35
|
expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.4)
|
32
36
|
subject
|
33
37
|
|
34
|
-
expect(element.state.
|
35
|
-
expect(element.state.
|
38
|
+
expect(element.state.opacity).to eq 0.4
|
39
|
+
expect(element.state.last_fill_opacity).to eq 0.4
|
40
|
+
expect(element.state.last_stroke_opacity).to eq 0.4
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
39
44
|
context 'with just fill opacity' do
|
40
45
|
it 'sets fill opacity and sets stroke opacity to 1' do
|
41
|
-
element.
|
46
|
+
element.computed_properties.fill_opacity = '0.4'
|
42
47
|
|
43
48
|
expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 1)
|
44
49
|
subject
|
45
50
|
|
46
|
-
expect(element.state.
|
47
|
-
expect(element.state.
|
51
|
+
expect(element.state.opacity).to eq 1
|
52
|
+
expect(element.state.last_fill_opacity).to eq 0.4
|
53
|
+
expect(element.state.last_stroke_opacity).to eq 1
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
51
|
-
context 'with an existing
|
57
|
+
context 'with an existing stroke opacity' do
|
52
58
|
it 'multiplies the new opacity by the old' do
|
53
|
-
element.state.
|
54
|
-
element.state.stroke_opacity = 0.8
|
59
|
+
element.state.opacity = 0.5
|
55
60
|
|
56
|
-
element.
|
57
|
-
element.
|
61
|
+
element.computed_properties.fill_opacity = '0.4'
|
62
|
+
element.computed_properties.stroke_opacity = '0.5'
|
58
63
|
|
59
|
-
expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.
|
64
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.25)
|
60
65
|
subject
|
61
66
|
|
62
|
-
expect(element.state.
|
63
|
-
expect(element.state.
|
67
|
+
expect(element.state.opacity).to eq 0.5
|
68
|
+
expect(element.state.last_fill_opacity).to eq 0.2
|
69
|
+
expect(element.state.last_stroke_opacity).to eq 0.25
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
67
73
|
context 'with stroke, fill, and opacity all specified' do
|
68
74
|
it 'choses the lower of them' do
|
69
|
-
element.
|
70
|
-
element.
|
71
|
-
element.
|
75
|
+
element.computed_properties.fill_opacity = '0.4'
|
76
|
+
element.computed_properties.stroke_opacity = '0.6'
|
77
|
+
element.computed_properties.opacity = '0.5'
|
72
78
|
|
73
|
-
expect(element).to receive(:add_call_and_enter).with('transparent', 0.
|
79
|
+
expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.3)
|
74
80
|
subject
|
75
81
|
|
76
|
-
expect(element.state.
|
77
|
-
expect(element.state.
|
82
|
+
expect(element.state.opacity).to eq 0.5
|
83
|
+
expect(element.state.last_fill_opacity).to eq 0.2
|
84
|
+
expect(element.state.last_stroke_opacity).to eq 0.3
|
78
85
|
end
|
79
86
|
end
|
80
87
|
end
|
@@ -20,7 +20,8 @@ describe Prawn::SVG::Attributes::Transform do
|
|
20
20
|
let(:transform) { 'translate(-5.5)' }
|
21
21
|
|
22
22
|
it 'passes the transform and executes the returned matrix' do
|
23
|
-
expect(element).to receive(:parse_transform_attribute).with(transform)
|
23
|
+
expect(element).to receive(:parse_transform_attribute).with(transform)
|
24
|
+
expect(element).to receive(:matrix_for_pdf).and_return([1, 2, 3, 4, 5, 6])
|
24
25
|
expect(element).to receive(:add_call_and_enter).with('transformation_matrix', 1, 2, 3, 4, 5, 6)
|
25
26
|
|
26
27
|
element.attributes['transform'] = transform
|
@@ -32,7 +33,8 @@ describe Prawn::SVG::Attributes::Transform do
|
|
32
33
|
let(:transform) { 'translate(0)' }
|
33
34
|
|
34
35
|
it 'does not execute any commands' do
|
35
|
-
expect(element).to receive(:parse_transform_attribute).with(transform)
|
36
|
+
expect(element).to receive(:parse_transform_attribute).with(transform)
|
37
|
+
expect(element).to receive(:matrix_for_pdf).and_return([1, 0, 0, 1, 0, 0])
|
36
38
|
expect(element).not_to receive(:add_call_and_enter)
|
37
39
|
|
38
40
|
element.attributes['transform'] = transform
|
@@ -43,6 +45,7 @@ describe Prawn::SVG::Attributes::Transform do
|
|
43
45
|
context 'when transform is blank' do
|
44
46
|
it 'does nothing' do
|
45
47
|
expect(element).not_to receive(:parse_transform_attribute)
|
48
|
+
expect(element).not_to receive(:matrix_for_pdf)
|
46
49
|
expect(element).not_to receive(:add_call_and_enter)
|
47
50
|
|
48
51
|
subject
|
@@ -5,7 +5,7 @@ describe Prawn::SVG::Calculators::Pixels do
|
|
5
5
|
include Prawn::SVG::Calculators::Pixels
|
6
6
|
|
7
7
|
def computed_properties
|
8
|
-
Struct.new(:
|
8
|
+
Struct.new(:numeric_font_size).new(16)
|
9
9
|
end
|
10
10
|
|
11
11
|
[:x, :y, :pixels, :x_pixels, :y_pixels].each { |method| public method }
|
@@ -35,7 +35,6 @@ describe Prawn::SVG::Calculators::Pixels do
|
|
35
35
|
expect(subject.pixels(32)).to eq 32.0
|
36
36
|
expect(subject.pixels(32.0)).to eq 32.0
|
37
37
|
expect(subject.pixels('32')).to eq 32.0
|
38
|
-
expect(subject.pixels('32unknown')).to eq 32.0
|
39
38
|
expect(subject.pixels('32px')).to eq 32.0
|
40
39
|
expect(subject.pixels('32pt')).to eq 32.0
|
41
40
|
expect(subject.pixels('32in')).to eq 32.0 * 72
|
@@ -1,74 +1,44 @@
|
|
1
1
|
require "#{File.dirname(__FILE__)}/../../spec_helper"
|
2
2
|
|
3
3
|
describe Prawn::SVG::Color do
|
4
|
-
describe '::
|
5
|
-
|
6
|
-
Prawn::SVG::
|
7
|
-
|
8
|
-
|
9
|
-
it 'converts #xxxxxx to a hex value' do
|
10
|
-
Prawn::SVG::Color.css_color_to_prawn_color('#9ab123').should == '9ab123'
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'converts an html colour name to a hex value' do
|
14
|
-
Prawn::SVG::Color.css_color_to_prawn_color('White').should == 'ffffff'
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'converts an rgb string to a hex value' do
|
18
|
-
Prawn::SVG::Color.css_color_to_prawn_color('rgb(16, 32, 48)').should
|
19
|
-
Prawn::SVG::Color.css_color_to_prawn_color('rgb(-5, 50%, 120%)').should == '007fff'
|
4
|
+
describe '::parse' do
|
5
|
+
def parse(value)
|
6
|
+
values = Prawn::SVG::CSS::ValuesParser.parse(value)
|
7
|
+
Prawn::SVG::Color.parse(values[0])
|
20
8
|
end
|
21
9
|
|
22
|
-
it 'converts
|
23
|
-
expect(Prawn::SVG::Color.
|
24
|
-
expect(Prawn::SVG::Color.css_color_to_prawn_color('device-cmyk(-5, 50%, 120%, -5%)')).to eq [0, 50, 100, 0]
|
10
|
+
it 'converts #xxx to an RGB color' do
|
11
|
+
expect(parse('#9ab')).to eq Prawn::SVG::Color::RGB.new('99aabb')
|
25
12
|
end
|
26
13
|
|
27
|
-
it '
|
28
|
-
Prawn::SVG::Color.
|
14
|
+
it 'converts #xxxxxx to an RGB color' do
|
15
|
+
expect(parse('#9ab123')).to eq Prawn::SVG::Color::RGB.new('9ab123')
|
29
16
|
end
|
30
17
|
|
31
|
-
it '
|
32
|
-
expect(
|
18
|
+
it 'converts an html colour name to an RGB color' do
|
19
|
+
expect(parse('White')).to eq Prawn::SVG::Color::RGB.new('ffffff')
|
33
20
|
end
|
34
21
|
|
35
|
-
it
|
36
|
-
expect(
|
22
|
+
it 'converts an rgb function to an RGB color' do
|
23
|
+
expect(parse('rgb(16, 32, 48)')).to eq Prawn::SVG::Color::RGB.new('102030')
|
24
|
+
expect(parse('rgb(-5, 50%, 120%)')).to eq Prawn::SVG::Color::RGB.new('007fff')
|
37
25
|
end
|
38
26
|
|
39
|
-
it
|
40
|
-
expect(
|
27
|
+
it 'converts a CMYK string to an array of numbers' do
|
28
|
+
expect(parse('device-cmyk(0, 0.32, 0.48, 1.2)')).to eq Prawn::SVG::Color::CMYK.new([0, 32, 48, 100])
|
29
|
+
expect(parse('device-cmyk(0, 50%, 120%, -5%)')).to eq Prawn::SVG::Color::CMYK.new([0, 50, 100, 0])
|
41
30
|
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '::parse' do
|
45
|
-
let(:gradients) { { 'flan' => flan_gradient, 'drob' => drob_gradient } }
|
46
|
-
let(:flan_gradient) { double }
|
47
|
-
let(:drob_gradient) { double }
|
48
31
|
|
49
|
-
it
|
50
|
-
|
51
|
-
expect(results).to eq [
|
52
|
-
flan_gradient,
|
53
|
-
Prawn::SVG::Color::RGB.new('008000'),
|
54
|
-
Prawn::SVG::Color::RGB.new('112233')
|
55
|
-
]
|
32
|
+
it "returns nil if the color doesn't exist" do
|
33
|
+
expect(parse('blurble')).to be nil
|
56
34
|
end
|
57
35
|
|
58
|
-
it
|
59
|
-
|
60
|
-
expect(results).to eq [
|
61
|
-
Prawn::SVG::Color::RGB.new('008000'),
|
62
|
-
Prawn::SVG::Color::RGB.new('000000')
|
63
|
-
]
|
36
|
+
it 'returns nil if the function has the wrong number of arguments' do
|
37
|
+
expect(parse('rgb(-1, 0)')).to be nil
|
64
38
|
end
|
65
39
|
|
66
|
-
it
|
67
|
-
|
68
|
-
expect(results).to eq [
|
69
|
-
Prawn::SVG::Color::CMYK.new([100, 0, 100, 50]),
|
70
|
-
Prawn::SVG::Color::CMYK.new([0, 0, 0, 100])
|
71
|
-
]
|
40
|
+
it "returns nil if it doesn't recognise the function" do
|
41
|
+
expect(parse('hsl(0, 0, 0)')).to be nil
|
72
42
|
end
|
73
43
|
end
|
74
44
|
end
|
@@ -25,10 +25,22 @@ describe Prawn::SVG::Document do
|
|
25
25
|
context 'when unparsable XML is provided' do
|
26
26
|
let(:svg) { "this isn't SVG data" }
|
27
27
|
|
28
|
-
it
|
28
|
+
it "raises an exception, passing on REXML's error message" do
|
29
29
|
expect do
|
30
30
|
Prawn::SVG::Document.new(svg, bounds, options)
|
31
|
-
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
31
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
32
|
+
/\AThe data supplied is not a valid SVG document.+Malformed.+#{Regexp.escape(svg)}/m
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when broken XML is provided' do
|
37
|
+
let(:svg) { '<svg><g><rect></rect></svg>' }
|
38
|
+
|
39
|
+
it "raises an exception, passing on REXML's error message" do
|
40
|
+
expect do
|
41
|
+
Prawn::SVG::Document.new(svg, bounds, options)
|
42
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
43
|
+
/\AThe data supplied is not a valid SVG document.+Missing end tag for 'g'/m
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
@@ -36,10 +48,12 @@ describe Prawn::SVG::Document do
|
|
36
48
|
let(:svg) { 'some_file.svg' }
|
37
49
|
|
38
50
|
it "raises an exception letting them know what they've done" do
|
51
|
+
message = "The data supplied is not a valid SVG document. It looks like you've supplied a filename " \
|
52
|
+
'instead; use File.read(filename) to get the data from the file before you pass it to prawn-svg.'
|
53
|
+
|
39
54
|
expect do
|
40
55
|
Prawn::SVG::Document.new(svg, bounds, options)
|
41
|
-
end.to raise_error Prawn::SVG::Document::InvalidSVGData,
|
42
|
-
"The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg."
|
56
|
+
end.to raise_error Prawn::SVG::Document::InvalidSVGData, /\A#{Regexp.escape(message)}/
|
43
57
|
end
|
44
58
|
end
|
45
59
|
end
|
@@ -120,27 +120,27 @@ describe Prawn::SVG::Elements::Base do
|
|
120
120
|
end
|
121
121
|
|
122
122
|
it "doesn't change anything if 'none' fill attribute provided" do
|
123
|
-
element.properties.fill = 'none'
|
123
|
+
element.properties.fill = Prawn::SVG::Paint.parse('none')
|
124
124
|
expect(element).to_not receive(:add_call)
|
125
125
|
subject
|
126
126
|
end
|
127
127
|
|
128
128
|
it "uses the fill attribute's color" do
|
129
129
|
expect(element).to receive(:add_call).with('fill_color', 'ff0000')
|
130
|
-
element.properties.fill = 'red'
|
130
|
+
element.properties.fill = Prawn::SVG::Paint.parse('red')
|
131
131
|
subject
|
132
132
|
end
|
133
133
|
|
134
|
-
it "
|
135
|
-
|
136
|
-
element.
|
134
|
+
it "ignores the instruction if the fill attribute's color is unparseable" do
|
135
|
+
element.properties.fill = Prawn::SVG::Paint.parse('blarble')
|
136
|
+
expect(element).to_not receive(:add_call)
|
137
137
|
subject
|
138
138
|
end
|
139
139
|
|
140
140
|
it "uses the color attribute if 'currentColor' fill attribute provided" do
|
141
|
+
element.properties.fill = Prawn::SVG::Paint.parse('currentColor')
|
142
|
+
element.state.computed_properties.color = Prawn::SVG::Color::RGB.new('ff0000')
|
141
143
|
expect(element).to receive(:add_call).with('fill_color', 'ff0000')
|
142
|
-
element.properties.fill = 'currentColor'
|
143
|
-
element.state.computed_properties.color = 'red'
|
144
144
|
subject
|
145
145
|
end
|
146
146
|
|
@@ -159,11 +159,10 @@ describe Prawn::SVG::Elements::Base do
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
-
it
|
162
|
+
it 'specifies no color if the URL is unresolvable' do
|
163
163
|
expect(element).to_not receive(:add_call)
|
164
|
-
element.properties.fill = 'url()'
|
164
|
+
element.properties.fill = Prawn::SVG::Paint.parse('url(bad)')
|
165
165
|
subject
|
166
|
-
expect(element.computed_properties.fill).to eq 'none'
|
167
166
|
end
|
168
167
|
end
|
169
168
|
|
@@ -2,11 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Prawn::SVG::Elements::Gradient do
|
4
4
|
let(:document) { Prawn::SVG::Document.new(svg, [800, 600], { width: 800, height: 600 }) }
|
5
|
-
let(:
|
5
|
+
let(:root_element) { Prawn::SVG::Elements::Root.new(document, document.root, []) }
|
6
|
+
let(:element) { document.gradients['flag'] }
|
6
7
|
|
7
8
|
before do
|
8
|
-
|
9
|
-
element.process
|
9
|
+
root_element.process
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'object bounding box with linear gradient' do
|
@@ -27,17 +27,20 @@ describe Prawn::SVG::Elements::Gradient do
|
|
27
27
|
it 'returns correct gradient arguments for an element' do
|
28
28
|
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
29
29
|
expect(arguments).to eq(
|
30
|
-
from:
|
31
|
-
to:
|
32
|
-
|
33
|
-
|
30
|
+
from: [0.0, 0.0],
|
31
|
+
to: [0.2, 1.0],
|
32
|
+
wrap: :pad,
|
33
|
+
matrix: Matrix[[100.0, 0.0, 100.0], [0.0, -100.0, 100.0], [0.0, 0.0, 1.0]],
|
34
|
+
bounding_box: [100, 100, 200, 0],
|
35
|
+
stops: [
|
36
|
+
{ offset: 0, color: 'ff0000', opacity: 1.0 },
|
37
|
+
{ offset: 0.25, color: 'ff0000', opacity: 1.0 },
|
38
|
+
{ offset: 0.5, color: 'ffffff', opacity: 1.0 },
|
39
|
+
{ offset: 0.75, color: '0000ff', opacity: 1.0 },
|
40
|
+
{ offset: 1, color: '0000ff', opacity: 1.0 }
|
41
|
+
]
|
34
42
|
)
|
35
43
|
end
|
36
|
-
|
37
|
-
it "returns nil if the element doesn't have a bounding box" do
|
38
|
-
arguments = element.gradient_arguments(double(bounding_box: nil))
|
39
|
-
expect(arguments).to be nil
|
40
|
-
end
|
41
44
|
end
|
42
45
|
|
43
46
|
describe 'object bounding box with radial gradient' do
|
@@ -58,12 +61,20 @@ describe Prawn::SVG::Elements::Gradient do
|
|
58
61
|
it 'returns correct gradient arguments for an element' do
|
59
62
|
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
60
63
|
expect(arguments).to eq(
|
61
|
-
from:
|
62
|
-
to:
|
63
|
-
r1:
|
64
|
-
r2:
|
65
|
-
|
66
|
-
|
64
|
+
from: [0.5, 0.2],
|
65
|
+
to: [0.0, 0.2],
|
66
|
+
r1: 0,
|
67
|
+
r2: 0.8,
|
68
|
+
wrap: :pad,
|
69
|
+
matrix: Matrix[[100.0, 0.0, 100.0], [0.0, -100.0, 100.0], [0.0, 0.0, 1.0]],
|
70
|
+
bounding_box: [100, 100, 200, 0],
|
71
|
+
stops: [
|
72
|
+
{ offset: 0, color: 'ff0000', opacity: 1.0 },
|
73
|
+
{ offset: 0.25, color: 'ff0000', opacity: 1.0 },
|
74
|
+
{ offset: 0.5, color: 'ffffff', opacity: 1.0 },
|
75
|
+
{ offset: 0.75, color: '0000ff', opacity: 1.0 },
|
76
|
+
{ offset: 1, color: '0000ff', opacity: 1.0 }
|
77
|
+
]
|
67
78
|
)
|
68
79
|
end
|
69
80
|
end
|
@@ -79,12 +90,14 @@ describe Prawn::SVG::Elements::Gradient do
|
|
79
90
|
end
|
80
91
|
|
81
92
|
it 'returns correct gradient arguments for an element' do
|
82
|
-
arguments = element.gradient_arguments(double)
|
93
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
83
94
|
expect(arguments).to eq(
|
84
|
-
from:
|
85
|
-
to:
|
86
|
-
stops:
|
87
|
-
|
95
|
+
from: [100.0, 500.0],
|
96
|
+
to: [200.0, 600.0],
|
97
|
+
stops: [{ offset: 0, color: 'ff0000', opacity: 1.0 }, { offset: 1, color: '0000ff', opacity: 1.0 }],
|
98
|
+
matrix: Matrix[[1.0, 0.0, 0.0], [0.0, -1.0, 600.0], [0.0, 0.0, 1.0]],
|
99
|
+
wrap: :pad,
|
100
|
+
bounding_box: [100, 100, 200, 0]
|
88
101
|
)
|
89
102
|
end
|
90
103
|
end
|
@@ -100,14 +113,16 @@ describe Prawn::SVG::Elements::Gradient do
|
|
100
113
|
end
|
101
114
|
|
102
115
|
it 'returns correct gradient arguments for an element' do
|
103
|
-
arguments = element.gradient_arguments(double)
|
116
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
104
117
|
expect(arguments).to eq(
|
105
|
-
from:
|
106
|
-
to:
|
107
|
-
r1:
|
108
|
-
r2:
|
109
|
-
stops:
|
110
|
-
|
118
|
+
from: [100.0, 500.0],
|
119
|
+
to: [200.0, 600.0],
|
120
|
+
r1: 0,
|
121
|
+
r2: 150.0,
|
122
|
+
stops: [{ offset: 0, color: 'ff0000', opacity: 1.0 }, { offset: 1, color: '0000ff', opacity: 1.0 }],
|
123
|
+
matrix: Matrix[[1.0, 0.0, 0.0], [0.0, -1.0, 600.0], [0.0, 0.0, 1.0]],
|
124
|
+
wrap: :pad,
|
125
|
+
bounding_box: [100, 100, 200, 0]
|
111
126
|
)
|
112
127
|
end
|
113
128
|
end
|
@@ -115,7 +130,7 @@ describe Prawn::SVG::Elements::Gradient do
|
|
115
130
|
context 'when gradientTransform is specified' do
|
116
131
|
let(:svg) do
|
117
132
|
<<-SVG
|
118
|
-
<linearGradient id="flag" gradientTransform="translateX(
|
133
|
+
<linearGradient id="flag" gradientTransform="translateX(0.5) scale(2)" x1="0" y1="0" x2="1" y2="1">
|
119
134
|
<stop offset="0" stop-color="red"/>
|
120
135
|
<stop offset="1" stop-color="blue"/>
|
121
136
|
</linearGradient>
|
@@ -123,13 +138,54 @@ describe Prawn::SVG::Elements::Gradient do
|
|
123
138
|
end
|
124
139
|
|
125
140
|
it 'passes in the transform via the apply_transformations option' do
|
126
|
-
arguments = element.gradient_arguments(double(bounding_box: [
|
141
|
+
arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
142
|
+
|
143
|
+
expect(arguments).to eq(
|
144
|
+
from: [0.0, 0.0],
|
145
|
+
to: [1.0, 1.0],
|
146
|
+
stops: [{ offset: 0, color: 'ff0000', opacity: 1.0 }, { offset: 1, color: '0000ff', opacity: 1.0 }],
|
147
|
+
matrix: Matrix[[200.0, 0.0, 150.0], [0.0, -200.0, 100.0], [0.0, 0.0, 1.0]],
|
148
|
+
wrap: :pad,
|
149
|
+
bounding_box: [100, 100, 200, 0]
|
150
|
+
)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when a gradient is linked to another' do
|
155
|
+
let(:svg) do
|
156
|
+
<<-SVG
|
157
|
+
<svg>
|
158
|
+
<linearGradient id="flag" gradientUnits="userSpaceOnUse" x1="100" y1="500" x2="200" y2="600">
|
159
|
+
<stop offset="0" stop-color="red"/>
|
160
|
+
<stop offset="1" stop-color="blue"/>
|
161
|
+
</linearGradient>
|
162
|
+
|
163
|
+
<linearGradient id="flag-2" href="#flag" x1="150" x2="220" />
|
164
|
+
|
165
|
+
<linearGradient id="flag-3" href="#flag-2" x1="170" />
|
166
|
+
</svg>
|
167
|
+
SVG
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'correctly inherits the attributes from the parent element' do
|
171
|
+
arguments = document.gradients['flag-2'].gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
172
|
+
expect(arguments).to eq(
|
173
|
+
from: [150.0, 500.0],
|
174
|
+
to: [220.0, 600.0],
|
175
|
+
stops: [{ offset: 0, color: 'ff0000', opacity: 1.0 }, { offset: 1, color: '0000ff', opacity: 1.0 }],
|
176
|
+
matrix: Matrix[[1.0, 0.0, 0.0], [0.0, -1.0, 600.0], [0.0, 0.0, 1.0]],
|
177
|
+
wrap: :pad,
|
178
|
+
bounding_box: [100, 100, 200, 0]
|
179
|
+
)
|
127
180
|
|
181
|
+
arguments = document.gradients['flag-3'].gradient_arguments(double(bounding_box: [100, 100, 200, 0]))
|
128
182
|
expect(arguments).to eq(
|
129
|
-
from:
|
130
|
-
to:
|
131
|
-
stops:
|
132
|
-
|
183
|
+
from: [170.0, 500.0],
|
184
|
+
to: [220.0, 600.0],
|
185
|
+
stops: [{ offset: 0, color: 'ff0000', opacity: 1.0 }, { offset: 1, color: '0000ff', opacity: 1.0 }],
|
186
|
+
matrix: Matrix[[1.0, 0.0, 0.0], [0.0, -1.0, 600.0], [0.0, 0.0, 1.0]],
|
187
|
+
wrap: :pad,
|
188
|
+
bounding_box: [100, 100, 200, 0]
|
133
189
|
)
|
134
190
|
end
|
135
191
|
end
|
@@ -69,21 +69,19 @@ RSpec.describe Prawn::SVG::Elements::Marker do
|
|
69
69
|
['rectangle', [[-0.5, 600.0], 4.0, 3.0], {}, []],
|
70
70
|
['clip', [], {}, []],
|
71
71
|
['transformation_matrix', [0.3, 0, 0, 0.3, 0, 0], {}, []],
|
72
|
-
['
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
['
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
['restore', [], {}, []]
|
86
|
-
]]
|
72
|
+
['fill_color', ['000000'], {}, []],
|
73
|
+
['line_width', [1.0], {}, []],
|
74
|
+
['cap_style', [:butt], {}, []],
|
75
|
+
['join_style', [:miter], {}, []],
|
76
|
+
['undash', [], {}, []],
|
77
|
+
['save', [], {}, []],
|
78
|
+
['fill', [], {}, [
|
79
|
+
['move_to', [[0.0, 600.0]], {}, []],
|
80
|
+
['line_to', [[10.0, 595.0]], {}, []],
|
81
|
+
['line_to', [[0.0, 590.0]], {}, []],
|
82
|
+
['close_path', [], {}, []]
|
83
|
+
]],
|
84
|
+
['restore', [], {}, []]
|
87
85
|
]],
|
88
86
|
['restore', [], {}, []]
|
89
87
|
]
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::SVG::FuncIRI do
|
4
|
+
describe '.parse' do
|
5
|
+
it 'parses a URL' do
|
6
|
+
expect(described_class.parse('url(#foo)')).to eq(described_class.new('#foo'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'parses a URL with whitespace' do
|
10
|
+
expect(described_class.parse('url( #foo )')).to eq(described_class.new('#foo'))
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'parses a URL with quotes' do
|
14
|
+
expect(described_class.parse('url("#foo")')).to eq(described_class.new('#foo'))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'parses a URL with quotes and whitespace' do
|
18
|
+
expect(described_class.parse('url( "#foo" )')).to eq(described_class.new('#foo'))
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'parses a URL with double quotes' do
|
22
|
+
expect(described_class.parse('url("#foo")')).to eq(described_class.new('#foo'))
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'parses a URL with double quotes and whitespace' do
|
26
|
+
expect(described_class.parse('url( "#foo" )')).to eq(described_class.new('#foo'))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'parses a URL with single quotes' do
|
30
|
+
expect(described_class.parse("url('#foo')")).to eq(described_class.new('#foo'))
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'parses a URL with single quotes and whitespace' do
|
34
|
+
expect(described_class.parse("url( '#foo' )")).to eq(described_class.new('#foo'))
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'parses a URL with both single and double quotes' do
|
38
|
+
expect(described_class.parse('url("#foo")')).to eq(described_class.new('#foo'))
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'parses a URL with both single and double quotes and whitespace' do
|
42
|
+
expect(described_class.parse('url( "#foo" )')).to eq(described_class.new('#foo'))
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'parses a URL with both single and double quotes and whitespace' do
|
46
|
+
expect(described_class.parse('url( "#foo" )')).to eq(described_class.new('#foo'))
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'parses a URL with escaped quotes' do
|
50
|
+
expect(described_class.parse('url("\\#foo")')).to eq(described_class.new('#foo'))
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'ignores a non-URL value' do
|
54
|
+
expect(described_class.parse('foo')).to be_nil
|
55
|
+
expect(described_class.parse('foo(1)')).to be_nil
|
56
|
+
expect(described_class.parse('url(1, 2)')).to be_nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|