prawn-svg 0.12.0.3 → 0.12.0.4

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.
data/README.md CHANGED
@@ -50,9 +50,11 @@ prawn-svg is in its infancy and does not support the full SVG specifications. I
50
50
 
51
51
  - <tt>style</tt> tag, if css_parser gem is installed on the system (see CSS section below)
52
52
 
53
- - <tt>image</tt> tag, only with http/https schemes; does not support 'slice' preserveAspectRatio
54
-
55
- - attributes/styles: <tt>fill</tt>, <tt>stroke</tt>, <tt>stroke-width</tt>, <tt>opacity</tt>, <tt>fill-opacity</tt>, <tt>stroke-opacity</tt>, <tt>transform</tt>
53
+ - <tt>image</tt> tag, only with http/https schemes
54
+
55
+ - <tt>clipPath</tt> tag
56
+
57
+ - attributes/styles: <tt>fill</tt>, <tt>stroke</tt>, <tt>stroke-width</tt>, <tt>opacity</tt>, <tt>fill-opacity</tt>, <tt>stroke-opacity</tt>, <tt>transform</tt>, <tt>clip-path</tt>
56
58
 
57
59
  - transform methods: <tt>translate</tt>, <tt>rotate</tt>, <tt>scale</tt>, <tt>matrix</tt>
58
60
 
@@ -66,7 +68,7 @@ By default, prawn-svg has a fonts path of <tt>["/Library/Fonts", "/usr/share/fon
66
68
  Mac OS X and Debian Linux users. You can add to the font path:
67
69
 
68
70
  ```ruby
69
- Prawn::Svg.font_path << "/my/font/directory"
71
+ Prawn::Svg::Interface.font_path << "/my/font/directory"
70
72
  ```
71
73
 
72
74
  CSS
@@ -6,11 +6,11 @@ class Prawn::Svg::Document
6
6
  CSS_PARSER_LOADED = true
7
7
  rescue LoadError
8
8
  CSS_PARSER_LOADED = false
9
- end
10
-
9
+ end
10
+
11
11
  DEFAULT_WIDTH = 640
12
12
  DEFAULT_HEIGHT = 480
13
-
13
+
14
14
  # An +Array+ of warnings that occurred while parsing the SVG data.
15
15
  attr_reader :warnings
16
16
 
@@ -19,14 +19,15 @@ class Prawn::Svg::Document
19
19
 
20
20
  attr_reader :root,
21
21
  :actual_width, :actual_height, :width, :height, :x_offset, :y_offset, :cache_images,
22
- :css_parser
23
-
22
+ :css_parser, :elements_by_id
23
+
24
24
  def initialize(data, bounds, options)
25
25
  @css_parser = CssParser::Parser.new if CSS_PARSER_LOADED
26
26
 
27
27
  @root = REXML::Document.new(data).root
28
28
  @warnings = []
29
29
  @options = options
30
+ @elements_by_id = {}
30
31
  @cache_images = options[:cache_images]
31
32
  @actual_width, @actual_height = bounds # set this first so % width/heights can be used
32
33
 
@@ -39,9 +40,9 @@ class Prawn::Svg::Document
39
40
  @actual_width = points(@root.attributes['width'] || DEFAULT_WIDTH, :x)
40
41
  @actual_height = points(@root.attributes['height'] || DEFAULT_HEIGHT, :y)
41
42
  end
42
-
43
+
43
44
  if @options[:width]
44
- @width = @options[:width]
45
+ @width = @options[:width]
45
46
  @scale = @options[:width] / @actual_width.to_f
46
47
  elsif @options[:height]
47
48
  @height = @options[:height]
@@ -51,9 +52,9 @@ class Prawn::Svg::Document
51
52
  end
52
53
 
53
54
  @width ||= @actual_width * @scale
54
- @height ||= @actual_height * @scale
55
+ @height ||= @actual_height * @scale
55
56
  end
56
-
57
+
57
58
  def x(value)
58
59
  (points(value, :x) - @x_offset) * scale
59
60
  end
@@ -1,50 +1,54 @@
1
1
  class Prawn::Svg::Element
2
2
  attr_reader :document, :element, :parent_calls, :base_calls, :state, :attributes
3
3
  attr_accessor :calls
4
-
4
+
5
5
  def initialize(document, element, parent_calls, state)
6
6
  @document = document
7
7
  @element = element
8
8
  @parent_calls = parent_calls
9
9
  @state = state
10
10
  @base_calls = @calls = []
11
-
11
+
12
12
  combine_attributes_and_style_declarations
13
13
  apply_styles
14
-
14
+
15
15
  if id = @attributes["id"]
16
- state[:ids][id] = @base_calls
16
+ document.elements_by_id[id] = self
17
17
  end
18
18
  end
19
-
19
+
20
20
  def name
21
21
  @name ||= element.name
22
22
  end
23
-
23
+
24
24
  def each_child_element
25
25
  element.elements.each do |e|
26
26
  yield self.class.new(@document, e, @calls, @state.dup)
27
27
  end
28
28
  end
29
-
29
+
30
30
  def warnings
31
31
  @document.warnings
32
32
  end
33
-
33
+
34
34
  def add_call(name, *arguments)
35
35
  @calls << [name.to_s, arguments, []]
36
36
  end
37
-
37
+
38
38
  def add_call_and_enter(name, *arguments)
39
39
  @calls << [name.to_s, arguments, []]
40
40
  @calls = @calls.last.last
41
- end
42
-
41
+ end
42
+
43
43
  def append_calls_to_parent
44
44
  @parent_calls.concat(@base_calls)
45
45
  end
46
-
47
-
46
+
47
+ def add_calls_from_element(other)
48
+ @calls.concat other.base_calls
49
+ end
50
+
51
+
48
52
  protected
49
53
  def apply_styles
50
54
  # Transform
@@ -87,15 +91,30 @@ class Prawn::Svg::Element
87
91
  fill_opacity = clamp(@attributes['fill-opacity'].to_f, 0, 1) if @attributes['fill-opacity']
88
92
  stroke_opacity = clamp(@attributes['stroke-opacity'].to_f, 0, 1) if @attributes['stroke-opacity']
89
93
 
90
- if fill_opacity || stroke_opacity
94
+ if fill_opacity || stroke_opacity
91
95
  state[:fill_opacity] = (state[:fill_opacity] || 1) * (fill_opacity || 1)
92
96
  state[:stroke_opacity] = (state[:stroke_opacity] || 1) * (stroke_opacity || 1)
93
97
 
94
98
  add_call_and_enter 'transparent', state[:fill_opacity], state[:stroke_opacity]
95
99
  end
96
100
 
101
+ # Clip path
102
+ if clip_path = @attributes['clip-path']
103
+ if (matches = clip_path.strip.match(/\Aurl\(#(.*)\)\z/)).nil?
104
+ document.warnings << "Only clip-path attributes with the form 'url(#xxx)' are supported"
105
+ elsif (clip_path_element = @document.elements_by_id[matches[1]]).nil?
106
+ document.warnings << "clip-path ID '#{matches[1]}' not defined"
107
+ elsif clip_path_element.element.name != "clipPath"
108
+ document.warnings << "clip-path ID '#{matches[1]}' does not point to a clipPath tag"
109
+ else
110
+ add_call_and_enter 'save_graphics_state'
111
+ add_calls_from_element clip_path_element
112
+ add_call "clip"
113
+ end
114
+ end
115
+
97
116
  # Fill and stroke
98
- draw_types = []
117
+ draw_types = []
99
118
  [:fill, :stroke].each do |type|
100
119
  dec = @attributes[type.to_s]
101
120
  if dec == "none"
@@ -109,11 +128,11 @@ class Prawn::Svg::Element
109
128
 
110
129
  draw_types << type.to_s if state[type]
111
130
  end
112
-
131
+
113
132
  # Stroke width
114
- add_call('line_width', @document.distance(@attributes['stroke-width'])) if @attributes['stroke-width']
133
+ add_call('line_width', @document.distance(@attributes['stroke-width'])) if @attributes['stroke-width']
115
134
 
116
- # Fonts
135
+ # Fonts
117
136
  if size = @attributes['font-size']
118
137
  @state[:font_size] = size.to_f * @document.scale
119
138
  end
@@ -125,20 +144,20 @@ class Prawn::Svg::Element
125
144
  font_updated = true
126
145
  @state[:font_family] = family
127
146
  end
128
-
147
+
129
148
  if @state[:font_family] && font_updated
130
149
  if pdf_font = Prawn::Svg::Font.map_font_family_to_pdf_font(@state[:font_family], @state[:font_style])
131
150
  add_call_and_enter 'font', pdf_font
132
151
  else
133
152
  @document.warnings << "Font family '#{@state[:font_family]}' style '#{@state[:font_style] || 'normal'}' is not a known font."
134
153
  end
135
- end
136
-
154
+ end
155
+
137
156
  # Call fill, stroke, or both
138
157
  draw_type = draw_types.join("_and_")
139
- if draw_type != "" && !Prawn::Svg::Parser::CONTAINER_TAGS.include?(element.name)
140
- add_call_and_enter draw_type
141
- end
158
+ if draw_type != "" && !@state[:disable_drawing] && !Prawn::Svg::Parser::CONTAINER_TAGS.include?(element.name)
159
+ add_call_and_enter(draw_type)
160
+ end
142
161
  end
143
162
 
144
163
  def parse_css_method_calls(string)
@@ -150,7 +169,7 @@ class Prawn::Svg::Element
150
169
  end
151
170
 
152
171
  # TODO : use http://www.w3.org/TR/SVG11/types.html#ColorKeywords
153
- HTML_COLORS = {
172
+ HTML_COLORS = {
154
173
  'black' => "000000", 'green' => "008000", 'silver' => "c0c0c0", 'lime' => "00ff00",
155
174
  'gray' => "808080", 'olive' => "808000", 'white' => "ffffff", 'yellow' => "ffff00",
156
175
  'maroon' => "800000", 'navy' => "000080", 'red' => "ff0000", 'blue' => "0000ff",
@@ -173,26 +192,26 @@ class Prawn::Svg::Element
173
192
  value = m[n].to_f
174
193
  value *= 2.55 if m[n][-1..-1] == '%'
175
194
  "%02x" % clamp(value.round, 0, 255)
176
- end.join
177
- end
195
+ end.join
196
+ end
178
197
  end
179
198
  end
180
199
 
181
200
  def clamp(value, min_value, max_value)
182
201
  [[value, min_value].max, max_value].min
183
- end
184
-
202
+ end
203
+
185
204
  def combine_attributes_and_style_declarations
186
205
  if @document && @document.css_parser
187
206
  tag_style = @document.css_parser.find_by_selector(element.name)
188
207
  id_style = @document.css_parser.find_by_selector("##{element.attributes["id"]}") if element.attributes["id"]
189
-
208
+
190
209
  if classes = element.attributes["class"]
191
210
  class_styles = classes.strip.split(/\s+/).collect do |class_name|
192
211
  @document.css_parser.find_by_selector(".#{class_name}")
193
212
  end
194
213
  end
195
-
214
+
196
215
  element_style = element.attributes['style']
197
216
 
198
217
  style = [tag_style, class_styles, id_style, element_style].flatten.collect do |s|
@@ -204,7 +223,7 @@ class Prawn::Svg::Element
204
223
 
205
224
  @attributes = parse_css_declarations(style)
206
225
  element.attributes.each {|n,v| @attributes[n] = v unless @attributes[n]}
207
- end
226
+ end
208
227
 
209
228
  def parse_css_declarations(declarations)
210
229
  # copied from css_parser
@@ -6,7 +6,7 @@ module Prawn
6
6
  #
7
7
  # +options+ must contain the key :at, which takes a tuple of x and y co-ordinates.
8
8
  #
9
- # +options+ can optionally contain the key :width or :height. If both are
9
+ # +options+ can optionally contain the key :width or :height. If both are
10
10
  # specified, only :width will be used. If neither are specified, the resolution
11
11
  # given in the SVG will be used.
12
12
  #
@@ -18,7 +18,7 @@ module Prawn
18
18
  svg = Prawn::Svg::Interface.new(data, self, options)
19
19
  svg.draw
20
20
  {:warnings => svg.document.warnings, :width => svg.document.width, :height => svg.document.height}
21
- end
21
+ end
22
22
  end
23
23
  end
24
24
  end
@@ -7,7 +7,7 @@ class Prawn::Svg::Font
7
7
  "cursive" => "Times-Roman",
8
8
  "fantasy" => "Times-Roman",
9
9
  "monospace" => "Courier"}
10
-
10
+
11
11
  def self.map_font_family_to_pdf_font(font_family, font_style = nil)
12
12
  font_family.split(",").detect do |font|
13
13
  font = font.gsub(/['"]/, '').gsub(/\s{2,}/, ' ').strip.downcase
@@ -17,25 +17,25 @@ class Prawn::Svg::Font
17
17
 
18
18
  generic_font = GENERIC_CSS_FONT_MAPPING[font]
19
19
  break generic_font if generic_font
20
-
20
+
21
21
  break font.downcase if font_installed?(font, font_style)
22
22
  end
23
23
  end
24
-
24
+
25
25
  def self.font_path(font_family, font_style = nil)
26
26
  font_style = :normal if font_style.nil?
27
27
  if installed_styles = installed_fonts[font_family.downcase]
28
28
  installed_styles[font_style]
29
29
  end
30
30
  end
31
-
31
+
32
32
  def self.font_installed?(font_family, font_style = nil)
33
33
  !font_path(font_family, font_style).nil?
34
34
  end
35
35
 
36
36
  def self.installed_fonts
37
37
  return @installed_fonts if @installed_fonts
38
-
38
+
39
39
  fonts = {}
40
40
  Prawn::Svg::Interface.font_path.uniq.collect {|path| Dir["#{path}/*"]}.flatten.each do |filename|
41
41
  information = font_information(filename) rescue nil
@@ -46,14 +46,14 @@ class Prawn::Svg::Font
46
46
  when 'Bold Italic' then :bold_italic
47
47
  else :normal
48
48
  end
49
-
49
+
50
50
  (fonts[font_name.downcase] ||= {})[font_style] = filename
51
51
  end
52
52
  end
53
-
53
+
54
54
  @installed_fonts = fonts
55
55
  end
56
-
56
+
57
57
  def self.font_information(filename)
58
58
  File.open(filename, "r") do |f|
59
59
  x = f.read(12)
@@ -66,22 +66,22 @@ class Prawn::Svg::Font
66
66
  break tables[start+8..start+15].unpack("NN")
67
67
  end
68
68
  end
69
-
69
+
70
70
  return unless length
71
71
  f.seek(offset)
72
72
  data = f.read(length)
73
-
73
+
74
74
  format, name_count, string_offset = data[0..5].unpack("nnn")
75
-
75
+
76
76
  names = {}
77
77
  name_count.times do |index|
78
78
  start = 6 + index * 12
79
- platform_id, platform_specific_id, language_id, name_id, length, offset = data[start..start+11].unpack("nnnnnn")
79
+ platform_id, platform_specific_id, language_id, name_id, length, offset = data[start..start+11].unpack("nnnnnn")
80
80
  next unless language_id == 0 # English
81
81
  next unless name_id == 1 || name_id == 2
82
-
82
+
83
83
  offset += string_offset
84
- field = data[offset..offset+length-1]
84
+ field = data[offset..offset+length-1]
85
85
  names[name_id] = if platform_id == 0
86
86
  begin
87
87
  if field.respond_to?(:encode)
@@ -9,11 +9,11 @@ module Prawn
9
9
 
10
10
  @font_path = []
11
11
  DEFAULT_FONT_PATHS.each {|path| @font_path << path if File.exists?(path)}
12
-
12
+
13
13
  class << self; attr_accessor :font_path; end
14
-
14
+
15
15
  attr_reader :data, :prawn, :document, :options
16
-
16
+
17
17
  #
18
18
  # Creates a Prawn::Svg object.
19
19
  #
@@ -21,19 +21,19 @@ module Prawn
21
21
  #
22
22
  # +options+ must contain the key :at, which takes a tuple of x and y co-ordinates.
23
23
  #
24
- # +options+ can optionally contain the key :width or :height. If both are
24
+ # +options+ can optionally contain the key :width or :height. If both are
25
25
  # specified, only :width will be used.
26
26
  #
27
27
  def initialize(data, prawn, options)
28
28
  @data = data
29
29
  @prawn = prawn
30
30
  @options = options
31
-
31
+
32
32
  @options[:at] or raise "options[:at] must be specified"
33
33
 
34
34
  prawn.font_families.update(Prawn::Svg::Font.installed_fonts)
35
35
 
36
- @document = Document.new(data, [prawn.bounds.width, prawn.bounds.height], options)
36
+ @document = Document.new(data, [prawn.bounds.width, prawn.bounds.height], options)
37
37
  end
38
38
 
39
39
  #
@@ -47,12 +47,12 @@ module Prawn
47
47
  end
48
48
  end
49
49
 
50
-
51
- private
50
+
51
+ private
52
52
  def proc_creator(prawn, calls)
53
53
  Proc.new {issue_prawn_command(prawn, calls)}
54
54
  end
55
-
55
+
56
56
  def issue_prawn_command(prawn, calls)
57
57
  calls.each do |call, arguments, children|
58
58
  if rewrite_call_arguments(prawn, call, arguments) == false
@@ -66,21 +66,21 @@ module Prawn
66
66
  end
67
67
  end
68
68
  end
69
-
69
+
70
70
  def rewrite_call_arguments(prawn, call, arguments)
71
71
  if call == 'relative_draw_text'
72
72
  call.replace "draw_text"
73
73
  arguments.last[:at][0] = @relative_text_position if @relative_text_position
74
74
  end
75
-
75
+
76
76
  case call
77
77
  when 'text_group'
78
78
  @relative_text_position = nil
79
79
  false
80
-
80
+
81
81
  when 'draw_text'
82
82
  text, options = arguments
83
-
83
+
84
84
  width = prawn.width_of(text, options.merge(:kerning => true))
85
85
 
86
86
  if (anchor = options.delete(:text_anchor)) && %w(middle end).include?(anchor)
@@ -90,17 +90,21 @@ module Prawn
90
90
 
91
91
  space_width = prawn.width_of("n", options)
92
92
  @relative_text_position = options[:at][0] + width + space_width
93
-
93
+
94
94
  when 'transformation_matrix'
95
95
  x = prawn.bounds.absolute_left
96
96
  y = prawn.bounds.absolute_top
97
97
  arguments[4] += x - (x * arguments[0] - y * arguments[1])
98
98
  arguments[5] += y - (x * arguments[1] + y * arguments[0])
99
-
99
+
100
+ when 'clip'
101
+ prawn.add_content "W n" # clip to path
102
+ false
103
+
100
104
  when 'save'
101
105
  prawn.save_graphics_state
102
106
  false
103
-
107
+
104
108
  when 'restore'
105
109
  prawn.restore_graphics_state
106
110
  false
@@ -12,12 +12,12 @@ require 'rexml/document'
12
12
  # SVG to another format.
13
13
  #
14
14
  class Prawn::Svg::Parser
15
- CONTAINER_TAGS = %w(g svg symbol defs)
16
-
15
+ CONTAINER_TAGS = %w(g svg symbol defs clipPath)
16
+
17
17
  #
18
- # Construct a Parser object.
18
+ # Construct a Parser object.
19
19
  #
20
- # The +data+ argument is SVG data.
20
+ # The +data+ argument is SVG data.
21
21
  #
22
22
  # +bounds+ is a tuple [width, height] that specifies the bounds of the drawing space in points.
23
23
  #
@@ -40,16 +40,16 @@ class Prawn::Svg::Parser
40
40
  #
41
41
  def parse
42
42
  @document.warnings.clear
43
-
43
+
44
44
  calls = [['fill_color', '000000', []]]
45
45
  root_element = Prawn::Svg::Element.new(@document, @document.root, calls, :ids => {}, :fill => true)
46
-
46
+
47
47
  parse_element(root_element)
48
48
  calls
49
49
  end
50
50
 
51
51
 
52
- private
52
+ private
53
53
  REQUIRED_ATTRIBUTES = {
54
54
  "polyline" => %w(points),
55
55
  "polygon" => %w(points),
@@ -57,9 +57,9 @@ class Prawn::Svg::Parser
57
57
  "ellipse" => %w(rx ry),
58
58
  "rect" => %w(width height),
59
59
  "path" => %w(d),
60
- "image" => %w(width height)
60
+ "image" => %w(width height)
61
61
  }
62
-
62
+
63
63
  USE_NEW_CIRCLE_CALL = Prawn::Document.new.respond_to?(:circle)
64
64
  USE_NEW_ELLIPSE_CALL = Prawn::Document.new.respond_to?(:ellipse)
65
65
 
@@ -69,17 +69,18 @@ class Prawn::Svg::Parser
69
69
  if required_attributes = REQUIRED_ATTRIBUTES[element.name]
70
70
  return unless check_attrs_present(element, required_attributes)
71
71
  end
72
-
72
+
73
73
  case element.name
74
74
  when *CONTAINER_TAGS
75
+ do_not_append_calls = %w(symbol defs clipPath).include?(element.name)
76
+ element.state[:disable_drawing] = true if element.name == "clipPath"
77
+
75
78
  element.each_child_element do |child|
76
79
  element.add_call "save"
77
80
  parse_element(child)
78
81
  element.add_call "restore"
79
82
  end
80
-
81
- do_not_append_calls = %w(symbol defs).include?(element.name)
82
-
83
+
83
84
  when 'style'
84
85
  load_css_styles(element)
85
86
 
@@ -107,20 +108,20 @@ class Prawn::Svg::Parser
107
108
  [x(x), y(y)]
108
109
  end
109
110
  element.add_call "polygon", *points
110
-
111
+
111
112
  when 'circle'
112
113
  if USE_NEW_CIRCLE_CALL
113
- element.add_call "circle",
114
+ element.add_call "circle",
114
115
  [x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['r'])
115
116
  else
116
- element.add_call "circle_at",
117
+ element.add_call "circle_at",
117
118
  [x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], :radius => distance(attrs['r'])
118
119
  end
119
-
120
+
120
121
  when 'ellipse'
121
- element.add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at",
122
+ element.add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at",
122
123
  [x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['rx']), distance(attrs['ry'])
123
-
124
+
124
125
  when 'rect'
125
126
  radius = distance(attrs['rx'] || attrs['ry'])
126
127
  args = [[x(attrs['x'] || '0'), y(attrs['y'] || '0')], distance(attrs['width']), distance(attrs['height'])]
@@ -130,18 +131,18 @@ class Prawn::Svg::Parser
130
131
  else
131
132
  element.add_call "rectangle", *args
132
133
  end
133
-
134
+
134
135
  when 'path'
135
136
  parse_path(element)
136
-
137
+
137
138
  when 'use'
138
139
  parse_use(element)
139
140
 
140
141
  when 'title', 'desc', 'metadata'
141
142
  # ignore
142
143
  do_not_append_calls = true
143
-
144
- when 'font-face', 'clipPath'
144
+
145
+ when 'font-face'
145
146
  # not supported
146
147
  do_not_append_calls = true
147
148
 
@@ -152,11 +153,11 @@ class Prawn::Svg::Parser
152
153
  else
153
154
  @document.warnings << "Unknown tag '#{element.name}'; ignoring"
154
155
  end
155
-
156
+
156
157
  element.append_calls_to_parent unless do_not_append_calls
157
158
  end
158
159
 
159
-
160
+
160
161
  def parse_path(element)
161
162
  @svg_path ||= Path.new
162
163
 
@@ -179,21 +180,20 @@ class Prawn::Svg::Parser
179
180
  else
180
181
  element.add_call command
181
182
  end
182
- end
183
+ end
183
184
  end
184
-
185
+
185
186
  def parse_use(element)
186
187
  if href = element.attributes['xlink:href']
187
188
  if href[0..0] == '#'
188
189
  id = href[1..-1]
189
- if id_calls = element.state[:ids][id]
190
+ if definition_element = @document.elements_by_id[id]
190
191
  x = element.attributes['x']
191
192
  y = element.attributes['y']
192
193
  if x || y
193
194
  element.add_call_and_enter "translate", distance(x || 0), -distance(y || 0)
194
195
  end
195
-
196
- element.calls.concat(id_calls)
196
+ element.add_calls_from_element definition_element
197
197
  else
198
198
  @document.warnings << "no tag with ID '#{id}' was found, referenced by use tag"
199
199
  end
@@ -203,7 +203,7 @@ class Prawn::Svg::Parser
203
203
  else
204
204
  @document.warnings << "no xlink:href specified on use tag"
205
205
  end
206
- end
206
+ end
207
207
 
208
208
  ####################################################################################################################
209
209
 
@@ -215,8 +215,8 @@ class Prawn::Svg::Parser
215
215
  element.element.text
216
216
  end
217
217
 
218
- @document.css_parser.add_block!(data)
219
- end
218
+ @document.css_parser.add_block!(data)
219
+ end
220
220
  end
221
221
 
222
222
  def check_attrs_present(element, attrs)
@@ -226,7 +226,7 @@ class Prawn::Svg::Parser
226
226
  end
227
227
  missing_attrs.empty?
228
228
  end
229
-
229
+
230
230
  %w(x y distance).each do |method|
231
231
  define_method(method) {|*a| @document.send(method, *a)}
232
232
  end
@@ -44,20 +44,30 @@ class Prawn::Svg::Parser::Image
44
44
  par = (attrs['preserveAspectRatio'] || "xMidYMid meet").strip.split(/\s+/)
45
45
  par.shift if par.first == "defer"
46
46
  align, meet_or_slice = par
47
- raise Error, "slice preserveAspectRatio not supported by Prawn" if meet_or_slice == "slice"
47
+ slice = meet_or_slice == "slice"
48
+
49
+ if slice
50
+ element.add_call "save"
51
+ element.add_call "rectangle", [x, y], width, height
52
+ element.add_call "clip"
53
+ end
48
54
 
49
55
  options = {}
50
56
  case align
51
57
  when /\Ax(Min|Mid|Max)Y(Min|Mid|Max)\z/
52
- options[:fit] = [width, height]
53
58
  ratio = image_ratio(image)
54
- if width/height < ratio
59
+
60
+ options[:fit] = [width, height] unless slice
61
+
62
+ if (width/height > ratio) == slice
63
+ options[:width] = width if slice
55
64
  y -= case $2
56
65
  when "Min" then 0
57
66
  when "Mid" then (height - width/ratio)/2
58
67
  when "Max" then height - width/ratio
59
68
  end
60
69
  else
70
+ options[:height] = height if slice
61
71
  x += case $1
62
72
  when "Min" then 0
63
73
  when "Mid" then (width - height*ratio)/2
@@ -74,6 +84,7 @@ class Prawn::Svg::Parser::Image
74
84
  options[:at] = [x, y]
75
85
 
76
86
  element.add_call "image", FakeIO.new(image), options
87
+ element.add_call "restore" if slice
77
88
  rescue Error => e
78
89
  @document.warnings << e.message
79
90
  end
@@ -38,19 +38,19 @@ module Prawn
38
38
  raise InvalidError, "Invalid character '#{c}' in SVG path data"
39
39
  end
40
40
  end
41
-
41
+
42
42
  values << value.to_f if value != ""
43
43
  run_path_command(cmd, values) if cmd
44
-
44
+
45
45
  @calls
46
46
  end
47
-
48
-
47
+
48
+
49
49
  private
50
50
  def run_path_command(command, values)
51
51
  upcase_command = command.upcase
52
52
  relative = command != upcase_command
53
-
53
+
54
54
  case upcase_command
55
55
  when 'M' # moveto
56
56
  x = values.shift
@@ -60,19 +60,19 @@ module Prawn
60
60
  x += @last_point.first
61
61
  y += @last_point.last
62
62
  end
63
-
63
+
64
64
  @last_point = @subpath_initial_point = [x, y]
65
65
  @calls << ["move_to", @last_point]
66
-
66
+
67
67
  return run_path_command('L', values) if values.any?
68
-
68
+
69
69
  when 'Z' # closepath
70
70
  if @subpath_initial_point
71
71
  #@calls << ["line_to", @subpath_initial_point]
72
72
  @calls << ["close_path"]
73
73
  @last_point = @subpath_initial_point
74
74
  end
75
-
75
+
76
76
  when 'L' # lineto
77
77
  while values.any?
78
78
  x = values.shift
@@ -84,7 +84,7 @@ module Prawn
84
84
  @last_point = [x, y]
85
85
  @calls << ["line_to", @last_point]
86
86
  end
87
-
87
+
88
88
  when 'H' # horizontal lineto
89
89
  while values.any?
90
90
  x = values.shift
@@ -100,89 +100,89 @@ module Prawn
100
100
  @last_point = [@last_point.first, y]
101
101
  @calls << ["line_to", @last_point]
102
102
  end
103
-
103
+
104
104
  when 'C' # curveto
105
105
  while values.any?
106
106
  x1, y1, x2, y2, x, y = (1..6).collect {values.shift}
107
107
  if relative && @last_point
108
108
  x += @last_point.first
109
109
  x1 += @last_point.first
110
- x2 += @last_point.first
111
- y += @last_point.last
112
- y1 += @last_point.last
113
- y2 += @last_point.last
110
+ x2 += @last_point.first
111
+ y += @last_point.last
112
+ y1 += @last_point.last
113
+ y2 += @last_point.last
114
114
  end
115
-
115
+
116
116
  @last_point = [x, y]
117
117
  @previous_control_point = [x2, y2]
118
118
  @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
119
- end
119
+ end
120
120
 
121
121
  when 'S' # shorthand/smooth curveto
122
122
  while values.any?
123
123
  x2, y2, x, y = (1..4).collect {values.shift}
124
124
  if relative && @last_point
125
125
  x += @last_point.first
126
- x2 += @last_point.first
127
- y += @last_point.last
128
- y2 += @last_point.last
126
+ x2 += @last_point.first
127
+ y += @last_point.last
128
+ y2 += @last_point.last
129
129
  end
130
-
130
+
131
131
  if @previous_control_point
132
132
  x1 = 2 * @last_point.first - @previous_control_point.first
133
133
  y1 = 2 * @last_point.last - @previous_control_point.last
134
134
  else
135
135
  x1, y1 = @last_point
136
136
  end
137
-
137
+
138
138
  @last_point = [x, y]
139
- @previous_control_point = [x2, y2]
139
+ @previous_control_point = [x2, y2]
140
140
  @calls << ["curve_to", [x, y, x1, y1, x2, y2]]
141
141
  end
142
-
142
+
143
143
  when 'Q', 'T' # quadratic curveto
144
144
  while values.any?
145
145
  if shorthand = upcase_command == 'T'
146
- x, y = (1..2).collect {values.shift}
147
- else
146
+ x, y = (1..2).collect {values.shift}
147
+ else
148
148
  x1, y1, x, y = (1..4).collect {values.shift}
149
149
  end
150
-
150
+
151
151
  if relative && @last_point
152
152
  x += @last_point.first
153
153
  x1 += @last_point.first if x1
154
- y += @last_point.last
154
+ y += @last_point.last
155
155
  y1 += @last_point.last if y1
156
156
  end
157
-
158
- if shorthand
157
+
158
+ if shorthand
159
159
  if @previous_quadratic_control_point
160
160
  x1 = 2 * @last_point.first - @previous_quadratic_control_point.first
161
161
  y1 = 2 * @last_point.last - @previous_quadratic_control_point.last
162
162
  else
163
163
  x1, y1 = @last_point
164
164
  end
165
- end
166
-
165
+ end
166
+
167
167
  # convert from quadratic to cubic
168
168
  cx1 = @last_point.first + (x1 - @last_point.first) * 2 / 3.0
169
169
  cy1 = @last_point.last + (y1 - @last_point.last) * 2 / 3.0
170
170
  cx2 = cx1 + (x - @last_point.first) / 3.0
171
- cy2 = cy1 + (y - @last_point.last) / 3.0
171
+ cy2 = cy1 + (y - @last_point.last) / 3.0
172
172
 
173
173
  @last_point = [x, y]
174
174
  @previous_quadratic_control_point = [x1, y1]
175
-
175
+
176
176
  @calls << ["curve_to", [x, y, cx1, cy1, cx2, cy2]]
177
- end
178
-
177
+ end
178
+
179
179
  when 'A'
180
- # unsupported
180
+ # unsupported
181
181
  end
182
-
182
+
183
183
  @previous_control_point = nil unless %w(C S).include?(upcase_command)
184
184
  @previous_quadratic_control_point = nil unless %w(Q T).include?(upcase_command)
185
185
  end
186
186
  end
187
- end
187
+ end
188
188
  end
@@ -3,17 +3,17 @@ class Prawn::Svg::Parser::Text
3
3
  element.add_call_and_enter "text_group"
4
4
  internal_parse(element, [element.document.x(0)], [element.document.y(0)], false)
5
5
  end
6
-
6
+
7
7
  protected
8
8
  def internal_parse(element, x_positions, y_positions, relative)
9
9
  attrs = element.attributes
10
-
10
+
11
11
  if attrs['x'] || attrs['y']
12
12
  relative = false
13
13
  x_positions = attrs['x'].split(/[\s,]+/).collect {|n| element.document.x(n)} if attrs['x']
14
14
  y_positions = attrs['y'].split(/[\s,]+/).collect {|n| element.document.y(n)} if attrs['y']
15
15
  end
16
-
16
+
17
17
  if attrs['dx'] || attrs['dy']
18
18
  element.add_call_and_enter "translate", element.document.distance(attrs['dx'] || 0), -element.document.distance(attrs['dy'] || 0)
19
19
  end
@@ -25,18 +25,18 @@ class Prawn::Svg::Parser::Text
25
25
  if style = element.state[:font_style]
26
26
  opts[:style] = style
27
27
  end
28
-
28
+
29
29
  # This is not a prawn option but we can't work out how to render it here -
30
30
  # it's handled by Svg#rewrite_call_arguments
31
31
  if anchor = attrs['text-anchor']
32
- opts[:text_anchor] = anchor
32
+ opts[:text_anchor] = anchor
33
33
  end
34
34
 
35
35
  element.element.children.each do |child|
36
36
  if child.node_type == :text
37
- text = child.to_s.strip.gsub(/\s+/, " ")
37
+ text = child.value.strip.gsub(/\s+/, " ")
38
38
 
39
- while text != ""
39
+ while text != ""
40
40
  opts[:at] = [x_positions.first, y_positions.first]
41
41
 
42
42
  if x_positions.length > 1 || y_positions.length > 1
@@ -59,10 +59,10 @@ class Prawn::Svg::Parser::Text
59
59
  internal_parse(child_element, x_positions, y_positions, relative)
60
60
  child_element.append_calls_to_parent
61
61
  element.add_call 'restore'
62
-
62
+
63
63
  else
64
64
  element.warnings << "Unknown tag '#{child.name}' inside text tag; ignoring"
65
65
  end
66
- end
66
+ end
67
67
  end
68
68
  end
@@ -1,5 +1,5 @@
1
1
  module Prawn
2
2
  module Svg
3
- VERSION = '0.12.0.3'
3
+ VERSION = '0.12.0.4'
4
4
  end
5
5
  end
@@ -8,7 +8,7 @@ describe Prawn::Svg::Parser do
8
8
  <line x1="10%" y1="10%" x2="90%" y2="90%" />
9
9
  </svg>
10
10
  SVG
11
-
11
+
12
12
  document = Prawn::Svg::Document.new(svg, [2000, 2000], {})
13
13
  Prawn::Svg::Parser.new(document).parse[-2][-1].should == [["line", [100.0, 900.0, 900.0, 100.0], []]]
14
14
  end
@@ -19,18 +19,18 @@ describe Prawn::Svg::Parser do
19
19
  <line x1="1in" y1="1in" x2="9in" y2="9in" />
20
20
  </svg>
21
21
  SVG
22
-
22
+
23
23
  document = Prawn::Svg::Document.new(svg, [2000, 2000], {})
24
24
  Prawn::Svg::Parser.new(document).parse[-2][-1].should == [["line", [72.0, 720.0 - 72.0, 720.0 - 72.0, 72.0], []]]
25
25
  end
26
26
  end
27
-
27
+
28
28
  describe :parse_element do
29
29
  before(:each) do
30
30
  @document = Prawn::Svg::Document.new("<svg></svg>", [100, 100], {})
31
31
  @parser = Prawn::Svg::Parser.new(@document)
32
32
  end
33
-
33
+
34
34
  def mock_element(name, attributes = {})
35
35
  e = mock
36
36
  e.stub!(:name).and_return(name)
@@ -38,7 +38,7 @@ describe Prawn::Svg::Parser do
38
38
 
39
39
  Prawn::Svg::Element.new(@document, e, [], {})
40
40
  end
41
-
41
+
42
42
  it "ignores tags it doesn't know about" do
43
43
  calls = []
44
44
  @parser.send :parse_element, mock_element("unknown")
@@ -46,7 +46,7 @@ describe Prawn::Svg::Parser do
46
46
  @document.warnings.length.should == 1
47
47
  @document.warnings.first.should include("Unknown tag")
48
48
  end
49
-
49
+
50
50
  it "ignores tags that don't have all required attributes set" do
51
51
  calls = []
52
52
  @parser.send :parse_element, mock_element("ellipse", "rx" => "1")
@@ -4,13 +4,13 @@ describe Prawn::Svg::Parser::Path do
4
4
  before :each do
5
5
  @path = Prawn::Svg::Parser::Path.new
6
6
  end
7
-
8
- describe "command parsing" do
7
+
8
+ describe "command parsing" do
9
9
  it "correctly parses a valid path" do
10
10
  calls = []
11
11
  @path.stub!(:run_path_command) {|*args| calls << args}
12
12
  @path.parse("A12.34 -56.78 89B4 5 C 6,7 T QX 0 Z")
13
-
13
+
14
14
  calls.should == [
15
15
  ["A", [12.34, -56.78, 89]],
16
16
  ["B", [4, 5]],
@@ -19,19 +19,19 @@ describe Prawn::Svg::Parser::Path do
19
19
  ["Q", []],
20
20
  ["X", [0]],
21
21
  ["Z", []]
22
- ]
22
+ ]
23
23
  end
24
-
24
+
25
25
  it "correctly parses an empty path" do
26
26
  @path.should_not_receive(:run_path_command)
27
27
  @path.parse("").should == []
28
28
  @path.parse(" ").should == []
29
29
  end
30
-
30
+
31
31
  it "raises on invalid characters in the path" do
32
32
  lambda {@path.parse("M 10 % 20")}.should raise_error(Prawn::Svg::Parser::Path::InvalidError)
33
33
  end
34
-
34
+
35
35
  it "raises on numerical data before a command letter" do
36
36
  lambda {@path.parse("10 P")}.should raise_error(Prawn::Svg::Parser::Path::InvalidError)
37
37
  end
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Prawn::Svg::Interface do
3
+ describe Prawn::Svg::Interface do
4
4
  describe "sample file rendering" do
5
5
  root = "#{File.dirname(__FILE__)}/../.."
6
6
  files = Dir["#{root}/spec/sample_svg/*.svg"]
7
-
7
+
8
8
  it "has at least 10 SVG sample files to test" do
9
9
  files.length.should >= 10
10
10
  end
11
-
11
+
12
12
  files.each do |file|
13
13
  it "renders the #{File.basename file} sample file without warnings or crashing" do
14
14
  warnings = nil
@@ -0,0 +1,10 @@
1
+ <svg width="120" height="120" viewPort="0 0 120 120" version="1.1" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <clipPath id="myClip">
4
+ <circle cx="30" cy="30" r="20"/>
5
+ <circle cx="70" cy="70" r="20"/>
6
+ </clipPath>
7
+ </defs>
8
+
9
+ <rect x="10" y="10" width="100" height="100" fill="red" clip-path="url(#myClip)"/>
10
+ </svg>
@@ -4,7 +4,19 @@
4
4
  <svg width="210mm" height="297mm" viewBox="0 0 1050 1485"
5
5
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
6
6
 
7
+ <g transform="translate(0 50)">
8
+ <text y="50" font-size="12pt">mid/mid</text>
9
+ <text y="200" font-size="12pt">mid/mid</text>
10
+ <text y="350" font-size="12pt">mid/mid</text>
11
+ <text y="550" font-size="12pt">min/min</text>
12
+ <text y="700" font-size="12pt">min/min</text>
13
+ <text y="900" font-size="12pt">max/max</text>
14
+ <text y="1050" font-size="12pt">max/max</text>
15
+ </g>
16
+
7
17
  <g transform="translate(50 0)">
18
+ <text y="25" font-size="12pt">wide image, aspect ratio meet</text>
19
+
8
20
  <rect y="50" width="100" height="100" fill="none" stroke="blue" stroke-width="2"/>
9
21
  <image y="50" width="100" height="100" preserveAspectRatio="xMidYMid" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
10
22
 
@@ -28,6 +40,33 @@
28
40
  </g>
29
41
 
30
42
  <g transform="translate(250 0)">
43
+ <text y="25" font-size="12pt">wide image, aspect ratio slice</text>
44
+
45
+ <rect y="50" width="100" height="100" fill="none" stroke="blue" stroke-width="2"/>
46
+ <image y="50" width="100" height="100" preserveAspectRatio="xMidYMid slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
47
+
48
+ <rect y="200" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
49
+ <image y="200" width="150" height="100" preserveAspectRatio="xMidYMid slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
50
+
51
+ <rect y="350" width="100" height="150" fill="none" stroke="blue" stroke-width="2"/>
52
+ <image y="350" width="100" height="150" preserveAspectRatio="xMidYMid slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
53
+
54
+ <rect y="550" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
55
+ <image y="550" width="150" height="100" preserveAspectRatio="xMinYMin slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
56
+
57
+ <rect y="700" width="100" height="150" fill="none" stroke="blue" stroke-width="2"/>
58
+ <image y="700" width="100" height="150" preserveAspectRatio="xMinYMin slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
59
+
60
+ <rect y="900" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
61
+ <image y="900" width="150" height="100" preserveAspectRatio="xMaxYMax slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
62
+
63
+ <rect y="1050" width="100" height="150" fill="none" stroke="blue" stroke-width="2"/>
64
+ <image y="1050" width="100" height="150" preserveAspectRatio="xMaxYMax slice" xlink:href="http://files.myopera.com/baby2u/albums/423302/smiley-cool.jpg"></image>
65
+ </g>
66
+
67
+ <g transform="translate(450 0)">
68
+ <text y="25" font-size="12pt">long image, aspect ratio meet</text>
69
+
31
70
  <rect y="50" width="100" height="100" fill="none" stroke="blue" stroke-width="2"/>
32
71
  <image y="50" width="100" height="100" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
33
72
 
@@ -50,7 +89,34 @@
50
89
  <image y="1050" width="100" height="200" preserveAspectRatio="xMaxYMax" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
51
90
  </g>
52
91
 
53
- <g transform="translate(450 0)">
92
+ <g transform="translate(650 0)">
93
+ <text y="25" font-size="12pt">long image, aspect ratio slice</text>
94
+
95
+ <rect y="50" width="100" height="100" fill="none" stroke="blue" stroke-width="2"/>
96
+ <image y="50" width="100" height="100" preserveAspectRatio="xMidYMid slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
97
+
98
+ <rect y="200" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
99
+ <image y="200" width="150" height="100" preserveAspectRatio="xMidYMid slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
100
+
101
+ <rect y="350" width="100" height="200" fill="none" stroke="blue" stroke-width="2"/>
102
+ <image y="350" width="100" height="200" preserveAspectRatio="xMidYMid slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
103
+
104
+ <rect y="550" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
105
+ <image y="550" width="150" height="100" preserveAspectRatio="xMinYMin slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
106
+
107
+ <rect y="700" width="100" height="200" fill="none" stroke="blue" stroke-width="2"/>
108
+ <image y="700" width="100" height="200" preserveAspectRatio="xMinYMin slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
109
+
110
+ <rect y="900" width="150" height="100" fill="none" stroke="blue" stroke-width="2"/>
111
+ <image y="900" width="150" height="100" preserveAspectRatio="xMaxYMax slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
112
+
113
+ <rect y="1050" width="100" height="200" fill="none" stroke="blue" stroke-width="2"/>
114
+ <image y="1050" width="100" height="200" preserveAspectRatio="xMaxYMax slice" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
115
+ </g>
116
+
117
+ <g transform="translate(850 0)">
118
+ <text y="25" font-size="12pt">aspect ratio preservation disabled</text>
119
+
54
120
  <rect y="50" width="100" height="100" fill="none" stroke="blue" stroke-width="2"/>
55
121
  <image y="50" width="100" height="100" preserveAspectRatio="none" xlink:href="http://imalbum.aufeminin.com/album/D20090809/583007_KWWH1ZQ8FU5ATJXSR84C5MRBUWW33L_989174388_H143954_L.jpg"></image>
56
122
 
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="10cm" height="3cm" viewBox="0 0 1000 300" xmlns="http://www.w3.org/2000/svg" version="1.1">
4
+ <g font-family="Verdana" font-size="24">
5
+ <text x="200" y="150" fill="blue">
6
+ More &amp; more people say &quot;Less is &lt; and
7
+ more is &gt;.&quot;
8
+ </text>
9
+ </g>
10
+ <rect x="1" y="1" width="998" height="298" fill="none" stroke="blue" stroke-width="2" />
11
+ </svg>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn-svg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0.3
4
+ version: 0.12.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2013-04-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: prawn
@@ -93,6 +93,7 @@ files:
93
93
  - spec/sample_output/directory
94
94
  - spec/sample_svg/arcs01.svg
95
95
  - spec/sample_svg/circle01.svg
96
+ - spec/sample_svg/clip_path.svg
96
97
  - spec/sample_svg/close_path.svg
97
98
  - spec/sample_svg/cubic01.svg
98
99
  - spec/sample_svg/cubic01a.svg
@@ -112,6 +113,7 @@ files:
112
113
  - spec/sample_svg/rect02.svg
113
114
  - spec/sample_svg/rotate_scale.svg
114
115
  - spec/sample_svg/scruffy_graph.svg
116
+ - spec/sample_svg/text_entities.svg
115
117
  - spec/sample_svg/triangle01.svg
116
118
  - spec/sample_svg/tspan01.svg
117
119
  - spec/sample_svg/tspan02.svg
@@ -154,6 +156,7 @@ test_files:
154
156
  - spec/sample_output/directory
155
157
  - spec/sample_svg/arcs01.svg
156
158
  - spec/sample_svg/circle01.svg
159
+ - spec/sample_svg/clip_path.svg
157
160
  - spec/sample_svg/close_path.svg
158
161
  - spec/sample_svg/cubic01.svg
159
162
  - spec/sample_svg/cubic01a.svg
@@ -173,6 +176,7 @@ test_files:
173
176
  - spec/sample_svg/rect02.svg
174
177
  - spec/sample_svg/rotate_scale.svg
175
178
  - spec/sample_svg/scruffy_graph.svg
179
+ - spec/sample_svg/text_entities.svg
176
180
  - spec/sample_svg/triangle01.svg
177
181
  - spec/sample_svg/tspan01.svg
178
182
  - spec/sample_svg/tspan02.svg