prawn-svg 0.21.0 → 0.22.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/.travis.yml +6 -0
- data/README.md +11 -4
- data/lib/prawn-svg.rb +9 -6
- data/lib/prawn/svg/attributes.rb +6 -0
- data/lib/prawn/svg/attributes/clip_path.rb +17 -0
- data/lib/prawn/svg/attributes/display.rb +5 -0
- data/lib/prawn/svg/attributes/font.rb +38 -0
- data/lib/prawn/svg/attributes/opacity.rb +15 -0
- data/lib/prawn/svg/attributes/stroke.rb +35 -0
- data/lib/prawn/svg/attributes/transform.rb +50 -0
- data/lib/prawn/svg/calculators/aspect_ratio.rb +1 -1
- data/lib/prawn/svg/calculators/document_sizing.rb +2 -2
- data/lib/prawn/svg/calculators/pixels.rb +1 -1
- data/lib/prawn/svg/color.rb +44 -14
- data/lib/prawn/svg/document.rb +6 -5
- data/lib/prawn/svg/elements.rb +33 -0
- data/lib/prawn/svg/elements/base.rb +228 -0
- data/lib/prawn/svg/elements/circle.rb +25 -0
- data/lib/prawn/svg/elements/container.rb +15 -0
- data/lib/prawn/svg/elements/ellipse.rb +23 -0
- data/lib/prawn/svg/elements/gradient.rb +117 -0
- data/lib/prawn/svg/elements/ignored.rb +5 -0
- data/lib/prawn/svg/elements/image.rb +85 -0
- data/lib/prawn/svg/elements/line.rb +16 -0
- data/lib/prawn/svg/elements/path.rb +405 -0
- data/lib/prawn/svg/elements/polygon.rb +17 -0
- data/lib/prawn/svg/elements/polyline.rb +22 -0
- data/lib/prawn/svg/elements/rect.rb +33 -0
- data/lib/prawn/svg/elements/root.rb +9 -0
- data/lib/prawn/svg/elements/style.rb +10 -0
- data/lib/prawn/svg/elements/text.rb +87 -0
- data/lib/prawn/svg/elements/use.rb +29 -0
- data/lib/prawn/svg/extension.rb +2 -2
- data/lib/prawn/svg/font.rb +3 -3
- data/lib/prawn/svg/interface.rb +12 -5
- data/lib/prawn/svg/url_loader.rb +1 -1
- data/lib/prawn/svg/version.rb +2 -2
- data/prawn-svg.gemspec +3 -3
- data/spec/integration_spec.rb +59 -2
- data/spec/prawn/svg/attributes/font_spec.rb +49 -0
- data/spec/prawn/svg/attributes/transform_spec.rb +56 -0
- data/spec/prawn/svg/calculators/aspect_ratio_spec.rb +2 -2
- data/spec/prawn/svg/calculators/document_sizing_spec.rb +3 -3
- data/spec/prawn/svg/color_spec.rb +36 -15
- data/spec/prawn/svg/document_spec.rb +4 -4
- data/spec/prawn/svg/elements/base_spec.rb +125 -0
- data/spec/prawn/svg/elements/gradient_spec.rb +61 -0
- data/spec/prawn/svg/elements/path_spec.rb +123 -0
- data/spec/prawn/svg/elements/style_spec.rb +23 -0
- data/spec/prawn/svg/{parser → elements}/text_spec.rb +7 -8
- data/spec/prawn/svg/font_spec.rb +12 -12
- data/spec/prawn/svg/interface_spec.rb +7 -7
- data/spec/prawn/svg/url_loader_spec.rb +2 -2
- data/spec/sample_svg/gradients.svg +40 -0
- data/spec/sample_svg/rect02.svg +8 -11
- data/spec/spec_helper.rb +1 -1
- metadata +46 -18
- data/lib/prawn/svg/element.rb +0 -304
- data/lib/prawn/svg/parser.rb +0 -268
- data/lib/prawn/svg/parser/image.rb +0 -81
- data/lib/prawn/svg/parser/path.rb +0 -392
- data/lib/prawn/svg/parser/text.rb +0 -80
- data/spec/prawn/svg/element_spec.rb +0 -127
- data/spec/prawn/svg/parser/path_spec.rb +0 -89
- data/spec/prawn/svg/parser_spec.rb +0 -55
@@ -0,0 +1,33 @@
|
|
1
|
+
class Prawn::SVG::Elements::Rect < Prawn::SVG::Elements::Base
|
2
|
+
def parse
|
3
|
+
require_attributes 'width', 'height'
|
4
|
+
|
5
|
+
@x = x(attributes['x'] || '0')
|
6
|
+
@y = y(attributes['y'] || '0')
|
7
|
+
@width = distance(attributes['width'], :x)
|
8
|
+
@height = distance(attributes['height'], :y)
|
9
|
+
|
10
|
+
require_positive_value @width, @height
|
11
|
+
|
12
|
+
@radius = distance(attributes['rx'] || attributes['ry'])
|
13
|
+
if @radius
|
14
|
+
# If you implement separate rx and ry in the future, you'll want to change this
|
15
|
+
# so that rx is constrained to @width/2 and ry is constrained to @height/2.
|
16
|
+
max_value = [@width, @height].min / 2.0
|
17
|
+
@radius = clamp(@radius, 0, max_value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def apply
|
22
|
+
if @radius
|
23
|
+
# n.b. does not support both rx and ry being specified with different values
|
24
|
+
add_call "rounded_rectangle", [@x, @y], @width, @height, @radius
|
25
|
+
else
|
26
|
+
add_call "rectangle", [@x, @y], @width, @height
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def bounding_box
|
31
|
+
[@x, @y, @x + @width, @y - @height]
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Prawn::SVG::Elements::Root < Prawn::SVG::Elements::Base
|
2
|
+
def apply
|
3
|
+
add_call 'fill_color', '000000'
|
4
|
+
add_call 'transformation_matrix', @document.sizing.x_scale, 0, 0, @document.sizing.y_scale, 0, 0
|
5
|
+
add_call 'transformation_matrix', 1, 0, 0, 1, @document.sizing.x_offset, @document.sizing.y_offset
|
6
|
+
|
7
|
+
process_child_elements
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class Prawn::SVG::Elements::Text < Prawn::SVG::Elements::Base
|
2
|
+
def parse
|
3
|
+
case attributes['xml:space']
|
4
|
+
when 'preserve'
|
5
|
+
state[:preserve_space] = true
|
6
|
+
when 'default'
|
7
|
+
state[:preserve_space] = false
|
8
|
+
end
|
9
|
+
|
10
|
+
@relative = state[:text_relative] || false
|
11
|
+
|
12
|
+
if attributes['x'] || attributes['y']
|
13
|
+
@relative = false
|
14
|
+
@x_positions = attributes['x'].split(COMMA_WSP_REGEXP).collect {|n| document.x(n)} if attributes['x']
|
15
|
+
@y_positions = attributes['y'].split(COMMA_WSP_REGEXP).collect {|n| document.y(n)} if attributes['y']
|
16
|
+
end
|
17
|
+
|
18
|
+
@x_positions ||= state[:text_x_positions] || [document.x(0)]
|
19
|
+
@y_positions ||= state[:text_y_positions] || [document.y(0)]
|
20
|
+
end
|
21
|
+
|
22
|
+
def apply
|
23
|
+
raise SkipElementQuietly if state[:display] == "none"
|
24
|
+
|
25
|
+
add_call_and_enter "text_group" if name == 'text'
|
26
|
+
|
27
|
+
if attributes['dx'] || attributes['dy']
|
28
|
+
add_call_and_enter "translate", document.distance(attributes['dx'] || 0), -document.distance(attributes['dy'] || 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
opts = {}
|
32
|
+
if size = state[:font_size]
|
33
|
+
opts[:size] = size
|
34
|
+
end
|
35
|
+
opts[:style] = state[:font_subfamily]
|
36
|
+
|
37
|
+
# This is not a prawn option but we can't work out how to render it here -
|
38
|
+
# it's handled by SVG#rewrite_call_arguments
|
39
|
+
if (anchor = attributes['text-anchor'] || state[:text_anchor]) &&
|
40
|
+
['start', 'middle', 'end'].include?(anchor)
|
41
|
+
opts[:text_anchor] = anchor
|
42
|
+
end
|
43
|
+
|
44
|
+
if spacing = attributes['letter-spacing']
|
45
|
+
add_call_and_enter 'character_spacing', document.points(spacing)
|
46
|
+
end
|
47
|
+
|
48
|
+
source.children.each do |child|
|
49
|
+
if child.node_type == :text
|
50
|
+
text = child.value.strip.gsub(state[:preserve_space] ? /[\n\t]/ : /\s+/, " ")
|
51
|
+
|
52
|
+
while text != ""
|
53
|
+
opts[:at] = [@x_positions.first, @y_positions.first]
|
54
|
+
|
55
|
+
if @x_positions.length > 1 || @y_positions.length > 1
|
56
|
+
# TODO : isn't this just text.shift ?
|
57
|
+
add_call 'draw_text', text[0..0], opts.dup
|
58
|
+
text = text[1..-1]
|
59
|
+
|
60
|
+
@x_positions.shift if @x_positions.length > 1
|
61
|
+
@y_positions.shift if @y_positions.length > 1
|
62
|
+
else
|
63
|
+
add_call @relative ? 'relative_draw_text' : 'draw_text', text, opts.dup
|
64
|
+
@relative = true
|
65
|
+
break
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
elsif child.name == "tspan"
|
70
|
+
add_call 'save'
|
71
|
+
|
72
|
+
new_state = state.dup
|
73
|
+
new_state[:text_x_positions] = @x_positions
|
74
|
+
new_state[:text_y_positions] = @y_positions
|
75
|
+
new_state[:text_relative] = @relative
|
76
|
+
new_state[:text_anchor] = opts[:text_anchor]
|
77
|
+
|
78
|
+
Prawn::SVG::Elements::Text.new(document, child, calls, new_state).process
|
79
|
+
|
80
|
+
add_call 'restore'
|
81
|
+
|
82
|
+
else
|
83
|
+
warnings << "Unknown tag '#{child.name}' inside text tag; ignoring"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
|
2
|
+
def parse
|
3
|
+
require_attributes 'xlink:href'
|
4
|
+
|
5
|
+
href = attributes['xlink:href']
|
6
|
+
|
7
|
+
if href[0..0] != '#'
|
8
|
+
raise SkipElementError, "use tag has an href that is not a reference to an id; this is not supported"
|
9
|
+
end
|
10
|
+
|
11
|
+
id = href[1..-1]
|
12
|
+
@definition_element = @document.elements_by_id[id]
|
13
|
+
|
14
|
+
if @definition_element.nil?
|
15
|
+
raise SkipElementError, "no tag with ID '#{id}' was found, referenced by use tag"
|
16
|
+
end
|
17
|
+
|
18
|
+
@x = attributes['x']
|
19
|
+
@y = attributes['y']
|
20
|
+
end
|
21
|
+
|
22
|
+
def apply
|
23
|
+
if @x || @y
|
24
|
+
add_call_and_enter "translate", distance(@x || 0, :x), -distance(@y || 0, :y)
|
25
|
+
end
|
26
|
+
|
27
|
+
add_calls_from_element @definition_element
|
28
|
+
end
|
29
|
+
end
|
data/lib/prawn/svg/extension.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Prawn
|
2
|
-
module
|
2
|
+
module SVG
|
3
3
|
module Extension
|
4
4
|
#
|
5
5
|
# Draws an SVG document into the PDF.
|
@@ -15,7 +15,7 @@ module Prawn
|
|
15
15
|
# svg IO.read("example.svg"), :at => [100, 300], :width => 600
|
16
16
|
#
|
17
17
|
def svg(data, options = {}, &block)
|
18
|
-
svg = Prawn::
|
18
|
+
svg = Prawn::SVG::Interface.new(data, self, options, &block)
|
19
19
|
svg.draw
|
20
20
|
{:warnings => svg.document.warnings, :width => svg.document.sizing.output_width, :height => svg.document.sizing.output_height}
|
21
21
|
end
|
data/lib/prawn/svg/font.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Prawn::
|
1
|
+
class Prawn::SVG::Font
|
2
2
|
GENERIC_CSS_FONT_MAPPING = {
|
3
3
|
"serif" => "Times-Roman",
|
4
4
|
"sans-serif" => "Helvetica",
|
@@ -34,12 +34,12 @@ class Prawn::Svg::Font
|
|
34
34
|
# This method is passed prawn's font_families hash. It'll be pre-populated with the fonts that prawn natively
|
35
35
|
# supports. We'll add fonts we find in the font path to this hash.
|
36
36
|
def self.load_external_fonts(fonts)
|
37
|
-
Prawn::
|
37
|
+
Prawn::SVG::Interface.font_path.uniq.collect {|path| Dir["#{path}/**/*"]}.flatten.each do |filename|
|
38
38
|
information = font_information(filename) rescue nil
|
39
39
|
if information && font_name = (information[16] || information[1])
|
40
40
|
subfamily = (information[17] || information[2] || "normal").gsub(/\s+/, "_").downcase.to_sym
|
41
41
|
subfamily = :normal if subfamily == :regular
|
42
|
-
(fonts[font_name] ||= {})[subfamily]
|
42
|
+
(fonts[font_name] ||= {})[subfamily] ||= filename
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
data/lib/prawn/svg/interface.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#
|
2
|
-
# Prawn::
|
2
|
+
# Prawn::SVG::Interface makes a Prawn::SVG::Document instance, uses that object to parse the supplied
|
3
3
|
# SVG into Prawn-compatible method calls, and then calls the Prawn methods.
|
4
4
|
#
|
5
5
|
module Prawn
|
6
|
-
module
|
6
|
+
module SVG
|
7
7
|
class Interface
|
8
8
|
VALID_OPTIONS = [:at, :position, :vposition, :width, :height, :cache_images, :fallback_font_name]
|
9
9
|
|
@@ -17,7 +17,7 @@ module Prawn
|
|
17
17
|
attr_reader :data, :prawn, :document, :options
|
18
18
|
|
19
19
|
#
|
20
|
-
# Creates a Prawn::
|
20
|
+
# Creates a Prawn::SVG object.
|
21
21
|
#
|
22
22
|
# +data+ is the SVG data to convert. +prawn+ is your Prawn::Document object.
|
23
23
|
#
|
@@ -40,7 +40,7 @@ module Prawn
|
|
40
40
|
@prawn = prawn
|
41
41
|
@options = options
|
42
42
|
|
43
|
-
Prawn::
|
43
|
+
Prawn::SVG::Font.load_external_fonts(prawn.font_families)
|
44
44
|
|
45
45
|
@document = Document.new(data, [prawn.bounds.width, prawn.bounds.height], options, &block)
|
46
46
|
end
|
@@ -54,10 +54,17 @@ module Prawn
|
|
54
54
|
return
|
55
55
|
end
|
56
56
|
|
57
|
+
@document.warnings.clear
|
58
|
+
|
57
59
|
prawn.bounding_box(position, :width => @document.sizing.output_width, :height => @document.sizing.output_height) do
|
58
60
|
prawn.save_graphics_state do
|
59
61
|
clip_rectangle 0, 0, @document.sizing.output_width, @document.sizing.output_height
|
60
|
-
|
62
|
+
|
63
|
+
calls = []
|
64
|
+
root_element = Prawn::SVG::Elements::Root.new(@document, @document.root, calls, fill: true)
|
65
|
+
root_element.process
|
66
|
+
|
67
|
+
proc_creator(prawn, calls).call
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
data/lib/prawn/svg/url_loader.rb
CHANGED
data/lib/prawn/svg/version.rb
CHANGED
data/prawn-svg.gemspec
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/prawn/svg/version', __FILE__)
|
|
3
3
|
|
4
4
|
spec = Gem::Specification.new do |gem|
|
5
5
|
gem.name = 'prawn-svg'
|
6
|
-
gem.version = Prawn::
|
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
9
|
gem.has_rdoc = false
|
@@ -18,9 +18,9 @@ spec = Gem::Specification.new do |gem|
|
|
18
18
|
gem.name = "prawn-svg"
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.required_ruby_version = '>=
|
21
|
+
gem.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
|
-
gem.add_runtime_dependency "prawn", ">= 0.
|
23
|
+
gem.add_runtime_dependency "prawn", ">= 0.11.1", "< 3"
|
24
24
|
gem.add_runtime_dependency "css_parser", "~> 1.3"
|
25
25
|
gem.add_development_dependency "rspec", "~> 3.0"
|
26
26
|
gem.add_development_dependency "rake", "~> 10.1"
|
data/spec/integration_spec.rb
CHANGED
@@ -1,8 +1,65 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe "Integration test" do
|
4
4
|
root = "#{File.dirname(__FILE__)}/.."
|
5
5
|
|
6
|
+
describe "a basic SVG file" do
|
7
|
+
let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {}) }
|
8
|
+
let(:element) { Prawn::SVG::Elements::Root.new(document, document.root, [], {}) }
|
9
|
+
|
10
|
+
let(:svg) do
|
11
|
+
<<-SVG
|
12
|
+
<svg width="100" height="200">
|
13
|
+
<style><![CDATA[
|
14
|
+
#puppy { fill: red; }
|
15
|
+
.animal { fill: green; }
|
16
|
+
rect { fill: blue; }
|
17
|
+
]]></style>
|
18
|
+
|
19
|
+
<rect x="0" y="0" width="10" height="10"/>
|
20
|
+
<rect x="10" y="0" width="10" height="10" class="animal"/>
|
21
|
+
<rect x="20" y="0" width="10" height="10" class="animal" id="puppy"/>
|
22
|
+
<rect x="30" y="0" width="10" height="10" class="animal" id="puppy" style="fill: yellow;"/>
|
23
|
+
</svg>
|
24
|
+
SVG
|
25
|
+
end
|
26
|
+
|
27
|
+
it "is correctly converted to a call stack" do
|
28
|
+
element.process
|
29
|
+
|
30
|
+
expect(element.calls).to eq [
|
31
|
+
["fill_color", ["000000"], []],
|
32
|
+
["transformation_matrix", [1, 0, 0, 1, 0, 0], []],
|
33
|
+
["transformation_matrix", [1, 0, 0, 1, 0, 0], []],
|
34
|
+
["save", [], []], ["restore", [], []],
|
35
|
+
["save", [], []],
|
36
|
+
["fill_color", ["0000ff"], []],
|
37
|
+
["fill", [], [
|
38
|
+
["rectangle", [[0.0, 200.0], 10.0, 10.0], []]
|
39
|
+
]],
|
40
|
+
["restore", [], []],
|
41
|
+
["save", [], []],
|
42
|
+
["fill_color", ["008000"], []],
|
43
|
+
["fill", [], [
|
44
|
+
["rectangle", [[10.0, 200.0], 10.0, 10.0], []]
|
45
|
+
]],
|
46
|
+
["restore", [], []],
|
47
|
+
["save", [], []],
|
48
|
+
["fill_color", ["ff0000"], []],
|
49
|
+
["fill", [], [
|
50
|
+
["rectangle", [[20.0, 200.0], 10.0, 10.0], []]
|
51
|
+
]],
|
52
|
+
["restore", [], []],
|
53
|
+
["save", [], []],
|
54
|
+
["fill_color", ["ffff00"], []],
|
55
|
+
["fill", [], [
|
56
|
+
["rectangle", [[30.0, 200.0], 10.0, 10.0], []]
|
57
|
+
]],
|
58
|
+
["restore", [], []]
|
59
|
+
]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
6
63
|
context "with option :position" do
|
7
64
|
let(:svg) { IO.read("#{root}/spec/sample_svg/cubic01a.svg") }
|
8
65
|
|
@@ -51,7 +108,7 @@ describe Prawn::Svg::Interface do
|
|
51
108
|
doc.url_loader.url_cache["https://raw.githubusercontent.com/mogest/prawn-svg/master/spec/sample_images/mushroom-long.jpg"] = IO.read("#{root}/spec/sample_images/mushroom-long.jpg")
|
52
109
|
end
|
53
110
|
|
54
|
-
warnings = r[:warnings].reject {|w| w =~ /Verdana/ && w =~ /is not a known font/ }
|
111
|
+
warnings = r[:warnings].reject {|w| w =~ /Verdana/ && w =~ /is not a known font/ || w =~ /render gradients$/}
|
55
112
|
end
|
56
113
|
warnings.should == []
|
57
114
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::SVG::Attributes::Font do
|
4
|
+
class FontTestElement
|
5
|
+
include Prawn::SVG::Attributes::Font
|
6
|
+
|
7
|
+
attr_accessor :attributes, :warnings
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@state = {}
|
11
|
+
@warnings = []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:element) { FontTestElement.new }
|
16
|
+
let(:document) { double(fallback_font_name: "Times-Roman") }
|
17
|
+
|
18
|
+
before do
|
19
|
+
allow(element).to receive(:document).and_return(document)
|
20
|
+
element.attributes = {"font-family" => family}
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#parse_font_attributes_and_call" do
|
24
|
+
context "with a specified existing font" do
|
25
|
+
let(:family) { "Helvetica" }
|
26
|
+
|
27
|
+
it "uses a font if it can find it" do
|
28
|
+
expect(element).to receive(:add_call_and_enter).with("font", "Helvetica", style: :normal)
|
29
|
+
element.parse_font_attributes_and_call
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with a specified non-existing font" do
|
34
|
+
let(:family) { "Font That Doesn't Exist" }
|
35
|
+
|
36
|
+
it "uses the fallback font if specified" do
|
37
|
+
expect(element).to receive(:add_call_and_enter).with("font", "Times-Roman", style: :normal)
|
38
|
+
element.parse_font_attributes_and_call
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't call the font method if there's no fallback font" do
|
42
|
+
allow(document).to receive(:fallback_font_name).and_return(nil)
|
43
|
+
expect(element).to_not receive(:add_call_and_enter)
|
44
|
+
element.parse_font_attributes_and_call
|
45
|
+
expect(element.warnings.length).to eq 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::SVG::Attributes::Transform do
|
4
|
+
class TransformTestElement
|
5
|
+
include Prawn::SVG::Attributes::Transform
|
6
|
+
|
7
|
+
attr_accessor :attributes, :warnings
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@warnings = []
|
11
|
+
@attributes = {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:element) { TransformTestElement.new }
|
16
|
+
|
17
|
+
describe "#parse_transform_attribute_and_call" do
|
18
|
+
subject { element.send :parse_transform_attribute_and_call }
|
19
|
+
|
20
|
+
describe "translate" do
|
21
|
+
it "handles a missing y argument" do
|
22
|
+
expect(element).to receive(:add_call_and_enter).with('translate', -5.5, 0)
|
23
|
+
expect(element).to receive(:distance).with(-5.5, :x).and_return(-5.5)
|
24
|
+
expect(element).to receive(:distance).with(0.0, :y).and_return(0.0)
|
25
|
+
|
26
|
+
element.attributes['transform'] = 'translate(-5.5)'
|
27
|
+
subject
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "rotate" do
|
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
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|