prawn-svg 0.35.1 → 0.36.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +5 -1
- 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/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
|
@@ -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
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::SVG::Length do
|
4
|
+
describe '.parse' do
|
5
|
+
it 'parses a length' do
|
6
|
+
expect(described_class.parse('1.23em')).to eq(described_class.new(1.23, :em))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'parses a length with a positive sign' do
|
10
|
+
expect(described_class.parse('+1.23em')).to eq(described_class.new(1.23, :em))
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'parses a length with a negative sign' do
|
14
|
+
expect(described_class.parse('-1.23em')).to eq(described_class.new(-1.23, :em))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'parses a length with the unit in caps' do
|
18
|
+
expect(described_class.parse('1.23EM')).to eq(described_class.new(1.23, :em))
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'parses a length with no decimal points' do
|
22
|
+
expect(described_class.parse('1em')).to eq(described_class.new(1, :em))
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'parses a length with no unit' do
|
26
|
+
expect(described_class.parse('1.23')).to eq(described_class.new(1.23, nil))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'allows numbers without a leading zero' do
|
30
|
+
expect(described_class.parse('.23em')).to eq(described_class.new(0.23, :em))
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not allow numbers with a trailing dot' do
|
34
|
+
expect(described_class.parse('1.em')).to be nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not allow units it does not recognise' do
|
38
|
+
expect(described_class.parse('1.23foo')).to be nil
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when positive_only is true' do
|
42
|
+
it 'does not allow negative numbers' do
|
43
|
+
expect(described_class.parse('-1.23em', positive_only: true)).to be nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does allow zero' do
|
47
|
+
expect(described_class.parse('0em', positive_only: true)).to eq(described_class.new(0, :em))
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does allow positive numbers' do
|
51
|
+
expect(described_class.parse('1.23em', positive_only: true)).to eq(described_class.new(1.23, :em))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#to_pixels' do
|
57
|
+
it 'converts a em-unit length to pixels' do
|
58
|
+
expect(described_class.new(2.5, :em).to_pixels(nil, 12)).to eq(12 * 2.5)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'converts a rem-unit length to pixels' do
|
62
|
+
expect(described_class.new(2.5, :rem).to_pixels(nil, 12)).to eq(16 * 2.5)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'converts a ex-unit length to pixels' do
|
66
|
+
expect(described_class.new(2.5, :ex).to_pixels(nil, 12)).to eq(6 * 2.5)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'converts a pc-unit length to pixels' do
|
70
|
+
expect(described_class.new(2.5, :pc).to_pixels(nil, 12)).to eq(37.5)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'converts a in-unit length to pixels' do
|
74
|
+
expect(described_class.new(2.5, :in).to_pixels(nil, 12)).to eq(180)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'converts a cm-unit length to pixels' do
|
78
|
+
expect(described_class.new(2.5, :cm).to_pixels(nil, 12)).to be_within(0.001).of(70.866)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'converts a mm-unit length to pixels' do
|
82
|
+
expect(described_class.new(2.5, :mm).to_pixels(nil, 12)).to be_within(0.001).of(7.087)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns the value for an unknown unit' do
|
86
|
+
expect(described_class.new(2.5, nil).to_pixels(nil, 12)).to eq(2.5)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|