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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -5
  3. data/README.md +4 -7
  4. data/lib/prawn/svg/attributes/opacity.rb +23 -8
  5. data/lib/prawn/svg/attributes/stroke.rb +7 -9
  6. data/lib/prawn/svg/attributes/transform.rb +1 -1
  7. data/lib/prawn/svg/calculators/pixels.rb +9 -22
  8. data/lib/prawn/svg/color.rb +58 -59
  9. data/lib/prawn/svg/css/font_parser.rb +46 -0
  10. data/lib/prawn/svg/document.rb +5 -1
  11. data/lib/prawn/svg/elements/base.rb +22 -30
  12. data/lib/prawn/svg/elements/gradient.rb +99 -74
  13. data/lib/prawn/svg/elements/line.rb +1 -1
  14. data/lib/prawn/svg/elements/marker.rb +2 -0
  15. data/lib/prawn/svg/elements/root.rb +1 -1
  16. data/lib/prawn/svg/elements/text_component.rb +3 -3
  17. data/lib/prawn/svg/funciri.rb +14 -0
  18. data/lib/prawn/svg/gradient_renderer.rb +313 -0
  19. data/lib/prawn/svg/length.rb +43 -0
  20. data/lib/prawn/svg/paint.rb +67 -0
  21. data/lib/prawn/svg/percentage.rb +24 -0
  22. data/lib/prawn/svg/properties.rb +208 -104
  23. data/lib/prawn/svg/renderer.rb +5 -0
  24. data/lib/prawn/svg/state.rb +5 -3
  25. data/lib/prawn/svg/transform_parser.rb +19 -13
  26. data/lib/prawn/svg/transform_utils.rb +37 -0
  27. data/lib/prawn/svg/version.rb +1 -1
  28. data/lib/prawn-svg.rb +7 -3
  29. data/prawn-svg.gemspec +4 -4
  30. data/spec/prawn/svg/attributes/opacity_spec.rb +27 -20
  31. data/spec/prawn/svg/attributes/transform_spec.rb +5 -2
  32. data/spec/prawn/svg/calculators/pixels_spec.rb +1 -2
  33. data/spec/prawn/svg/color_spec.rb +22 -52
  34. data/spec/prawn/svg/elements/base_spec.rb +9 -10
  35. data/spec/prawn/svg/elements/gradient_spec.rb +92 -36
  36. data/spec/prawn/svg/elements/marker_spec.rb +13 -15
  37. data/spec/prawn/svg/funciri_spec.rb +59 -0
  38. data/spec/prawn/svg/length_spec.rb +89 -0
  39. data/spec/prawn/svg/paint_spec.rb +96 -0
  40. data/spec/prawn/svg/pathable_spec.rb +3 -3
  41. data/spec/prawn/svg/pdfmatrix_spec.rb +60 -0
  42. data/spec/prawn/svg/percentage_spec.rb +60 -0
  43. data/spec/prawn/svg/properties_spec.rb +124 -107
  44. data/spec/prawn/svg/transform_parser_spec.rb +13 -13
  45. data/spec/sample_svg/gradient_stress_test.svg +115 -0
  46. metadata +17 -5
  47. data/lib/prawn/svg/extensions/additional_gradient_transforms.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ed96a3ff982220af8dac781a878f0ca369c1a94e8c5de2cecf72afef93dcdbd
4
- data.tar.gz: a55e3412050fefc9e87166fad28824eeef4e4189729d5834917bda62153858f7
3
+ metadata.gz: b833a9af0fae6fd2934c6b5ef37bd6d6d90aba36fa9a161520ac6a9a1c19f9db
4
+ data.tar.gz: 550aa711e413cac65e8af39f029096e3606f84a852b982729ca0252e758805ac
5
5
  SHA512:
6
- metadata.gz: 035326e61829decc604f58f76c894aaecb807447e28de467016962ad326e147beeae1c398872eef68497a6bf6e0843b191585a8d2bedcd146b88c349c593af2b
7
- data.tar.gz: 1694340502019cd66a11eff627829b7438126530d2b43236c1760816115b1a0f816c90de94ae845e9a9b3a9d8a261d53681ad99f07e26fa13e31535594ad293f
6
+ metadata.gz: 9a522f7b4aa8f713fc453cc3d6061968fce1a28ab60e58f6c321b92979bcb909748a81b8c9cb9a373f918d152e969ea7d0974afd975c8fba7ae70c03cec18a25
7
+ data.tar.gz: 537a912b7daab1581662cabfc5de5776ebe771d15e448e99a7c7d6125eb29644bbc40de6508429f5a3451f16ebb226f53402320ef4430118b16d05913cd3ede4
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prawn-svg (0.35.0)
4
+ prawn-svg (0.36.0)
5
5
  css_parser (~> 1.6)
6
6
  matrix (~> 0.4.2)
7
7
  prawn (>= 0.11.1, < 3)
8
- rexml (>= 3.2.0, < 4)
8
+ rexml (>= 3.3.9, < 4)
9
9
 
10
10
  GEM
11
11
  remote: http://rubygems.org/
@@ -34,8 +34,7 @@ GEM
34
34
  rainbow (3.1.1)
35
35
  rake (13.2.1)
36
36
  regexp_parser (2.9.2)
37
- rexml (3.3.0)
38
- strscan
37
+ rexml (3.4.0)
39
38
  rspec (3.13.0)
40
39
  rspec-core (~> 3.13.0)
41
40
  rspec-expectations (~> 3.13.0)
@@ -63,7 +62,6 @@ GEM
63
62
  rubocop-ast (1.31.3)
64
63
  parser (>= 3.3.1.0)
65
64
  ruby-progressbar (1.13.0)
66
- strscan (3.1.0)
67
65
  ttfunk (1.8.0)
68
66
  bigdecimal (~> 3.1)
69
67
  unicode-display_width (2.5.0)
data/README.md CHANGED
@@ -62,7 +62,7 @@ prawn-svg supports most but not all of the full SVG 1.1 specification. It curre
62
62
  implementation of elliptical arc is a bit rough at the moment.
63
63
 
64
64
  - `<text>`, `<tspan>` and `<tref>` with attributes `x`, `y`, `dx`, `dy`, `rotate`, `textLength`, `lengthAdjust`,
65
- and with extra properties `text-anchor`, `text-decoration` (underline only), `font-size`, `font-family`,
65
+ and with extra properties `text-anchor`, `text-decoration` (underline only), `font`, `font-size`, `font-family`,
66
66
  `font-weight`, `font-style`, `letter-spacing`, `dominant-baseline` (middle only)
67
67
 
68
68
  - `<svg>`, `<g>` and `<symbol>`
@@ -80,13 +80,14 @@ prawn-svg supports most but not all of the full SVG 1.1 specification. It curre
80
80
  - `<marker>`
81
81
 
82
82
  - `<linearGradient>` and `<radialGradient>` are implemented on Prawn 2.2.0+ with attributes `gradientUnits` and
83
- `gradientTransform` (`spreadMethod` and `stop-opacity` are unimplemented.)
83
+ `gradientTransform`
84
84
 
85
85
  - `<switch>` and `<foreignObject>`, although prawn-svg cannot handle any data that is not SVG so `<foreignObject>`
86
86
  tags are always ignored.
87
87
 
88
88
  - properties: `clip-path`, `color`, `display`, `fill`, `fill-opacity`, `fill-rule`, `opacity`, `overflow`,
89
- `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-linejoin`, `stroke-opacity`, `stroke-width`
89
+ `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-linejoin`, `stroke-opacity`, `stroke-width`,
90
+ `visibility`
90
91
 
91
92
  - properties on lines, polylines, polygons and paths: `marker-end`, `marker-mid`, `marker-start`
92
93
 
@@ -114,10 +115,6 @@ In CSS selectors you can use element names, IDs, classes, attributes (existence,
114
115
  and all combinators (` `, `>`, `+`, `~`).
115
116
  The pseudo-classes `:first-child`, `:last-child` and `:nth-child(n)` (where n is a number) also work.
116
117
 
117
- Warning: Ruby versions less than 2.6.0 have a bug in the REXML XPath implementation which means under some
118
- conditions the `+` combinator will not pick up all matching elements. See `stylesheets_spec.rb` for an
119
- explanation if you're stuck on an old version of Ruby.
120
-
121
118
  Pseudo-elements and the other pseudo-classes are not supported. Specificity ordering is
122
119
  implemented, but `!important` is not.
123
120
 
@@ -1,15 +1,30 @@
1
1
  module Prawn::SVG::Attributes::Opacity
2
2
  def parse_opacity_attributes_and_call
3
- # We can't do nested opacities quite like the SVG requires, but this is close enough.
4
- opacity = properties.opacity.to_f.clamp(0, 1) if properties.opacity
5
- fill_opacity = properties.fill_opacity.to_f.clamp(0, 1) if properties.fill_opacity
6
- stroke_opacity = properties.stroke_opacity.to_f.clamp(0, 1) if properties.stroke_opacity
3
+ # The opacity property is not inherited, but the opacity applies to all children underneath the element.
4
+ #
5
+ # Having an opacity property on a parent, and again on a child, multiplies the parent and child's opacities
6
+ # when drawing the children.
7
+ #
8
+ # The fill-opacity and stroke-opacity properties are inherited, but children which have a different value
9
+ # are displayed at that opacity rather than multiplying the parent's fill/stroke opacity with the child's.
10
+ #
11
+ # opacity and fill/stroke opacity can both be applied to the same element, and they multiply together.
7
12
 
8
- if opacity || fill_opacity || stroke_opacity
9
- state.fill_opacity *= [opacity || 1, fill_opacity || 1].min
10
- state.stroke_opacity *= [opacity || 1, stroke_opacity || 1].min
13
+ opacity = computed_properties.opacity&.to_f&.clamp(0, 1)
14
+ fill_opacity = computed_properties.fill_opacity.to_f.clamp(0, 1)
15
+ stroke_opacity = computed_properties.stroke_opacity.to_f.clamp(0, 1)
11
16
 
12
- add_call_and_enter 'transparent', state.fill_opacity, state.stroke_opacity
17
+ state.opacity *= opacity if opacity
18
+
19
+ fill_opacity = (fill_opacity || 1) * state.opacity
20
+ stroke_opacity = (stroke_opacity || 1) * state.opacity
21
+
22
+ fill_opacity = stroke_opacity = 0 if computed_properties.visibility != 'visible'
23
+
24
+ if state.last_fill_opacity != fill_opacity || state.last_stroke_opacity != stroke_opacity
25
+ state.last_fill_opacity = fill_opacity
26
+ state.last_stroke_opacity = stroke_opacity
27
+ add_call_and_enter 'transparent', fill_opacity, stroke_opacity
13
28
  end
14
29
  end
15
30
  end
@@ -23,19 +23,17 @@ module Prawn::SVG::Attributes::Stroke
23
23
  # don't do anything
24
24
  when 'none'
25
25
  add_call('undash')
26
- else
27
- array = dasharray.split(Prawn::SVG::Elements::COMMA_WSP_REGEXP)
28
- array *= 2 if array.length.odd?
29
- number_array = array.map { |value| pixels(value) }
26
+ when Array
27
+ dasharray *= 2 if dasharray.length.odd?
28
+ values = dasharray.map { |value| pixels(value) }
30
29
 
31
- if number_array.any?(&:negative?)
32
- @document.warnings << "stroke-dasharray cannot have negative numbers; treating as 'none'"
33
- add_call('undash')
34
- elsif number_array.inject(0) { |a, b| a + b }.zero?
30
+ if values.inject(0) { |a, b| a + b }.zero?
35
31
  add_call('undash')
36
32
  else
37
- add_call('dash', number_array)
33
+ add_call('dash', values)
38
34
  end
35
+ else
36
+ raise "Unknown dasharray value: #{dasharray.inspect}"
39
37
  end
40
38
  end
41
39
  end
@@ -2,7 +2,7 @@ module Prawn::SVG::Attributes::Transform
2
2
  def parse_transform_attribute_and_call
3
3
  return unless (transform = attributes['transform'])
4
4
 
5
- matrix = parse_transform_attribute(transform)
5
+ matrix = matrix_for_pdf(parse_transform_attribute(transform))
6
6
  add_call_and_enter 'transformation_matrix', *matrix unless matrix == [1, 0, 0, 1, 0, 0]
7
7
  end
8
8
  end
@@ -1,25 +1,12 @@
1
1
  module Prawn::SVG::Calculators::Pixels
2
2
  class Measurement
3
- extend Prawn::Measurements
4
-
5
3
  def self.to_pixels(value, axis_length = nil, font_size: Prawn::SVG::Properties::EM)
6
- if value.is_a?(String)
7
- if (match = value.match(/\d(em|ex|pc|cm|mm|in)$/))
8
- case match[1]
9
- when 'em'
10
- value.to_f * font_size
11
- when 'ex'
12
- value.to_f * (font_size / 2.0) # we don't have access to the x-height, so this is an approximation approved by the CSS spec
13
- when 'pc'
14
- value.to_f * 15 # according to http://www.w3.org/TR/SVG11/coords.html
15
- else
16
- send("#{match[1]}2pt", value.to_f)
17
- end
18
- elsif value[-1..] == '%'
19
- value.to_f * axis_length / 100.0
20
- else
21
- value.to_f
22
- end
4
+ if value.respond_to?(:to_pixels)
5
+ value.to_pixels(axis_length, font_size)
6
+ elsif value.is_a?(String)
7
+ value = value.strip
8
+ value = Prawn::SVG::Length.parse(value) || Prawn::SVG::Percentage.parse(value)
9
+ value&.to_pixels(axis_length, font_size) || 0.0
23
10
  elsif value
24
11
  value.to_f
25
12
  end
@@ -40,16 +27,16 @@ module Prawn::SVG::Calculators::Pixels
40
27
 
41
28
  def pixels(value)
42
29
  value && Measurement.to_pixels(value, state.viewport_sizing.viewport_diagonal,
43
- font_size: computed_properties.numerical_font_size)
30
+ font_size: computed_properties.numeric_font_size)
44
31
  end
45
32
 
46
33
  def x_pixels(value)
47
34
  value && Measurement.to_pixels(value, state.viewport_sizing.viewport_width,
48
- font_size: computed_properties.numerical_font_size)
35
+ font_size: computed_properties.numeric_font_size)
49
36
  end
50
37
 
51
38
  def y_pixels(value)
52
39
  value && Measurement.to_pixels(value, state.viewport_sizing.viewport_height,
53
- font_size: computed_properties.numerical_font_size)
40
+ font_size: computed_properties.numeric_font_size)
54
41
  end
55
42
  end
@@ -1,6 +1,28 @@
1
1
  class Prawn::SVG::Color
2
- RGB = Struct.new(:value)
3
- CMYK = Struct.new(:value)
2
+ CMYK = Struct.new(:value) do
3
+ def to_cmyk
4
+ self
5
+ end
6
+ end
7
+
8
+ RGB = Struct.new(:value) do
9
+ def to_rgb
10
+ [value[0..1], value[2..3], value[4..5]].map { |h| h.to_i(16) / 255.0 }
11
+ end
12
+
13
+ def to_cmyk
14
+ r, g, b = rgb = to_rgb
15
+ k = 1 - rgb.max
16
+ if k == 1
17
+ CMYK.new([0, 0, 0, 100])
18
+ else
19
+ c = (1 - r - k) / (1 - k)
20
+ m = (1 - g - k) / (1 - k)
21
+ y = (1 - b - k) / (1 - k)
22
+ CMYK.new([c, m, y, k].map { |v| (v * 100).round })
23
+ end
24
+ end
25
+ end
4
26
 
5
27
  RGB_DEFAULT_COLOR = RGB.new('000000')
6
28
  CMYK_DEFAULT_COLOR = CMYK.new([0, 0, 0, 100])
@@ -156,63 +178,48 @@ class Prawn::SVG::Color
156
178
  }.freeze
157
179
 
158
180
  class << self
159
- def parse(color_string, gradients = nil, color_mode = :rgb)
160
- url_specified = false
181
+ def black
182
+ RGB_DEFAULT_COLOR
183
+ end
161
184
 
162
- values = ::Prawn::SVG::CSS::ValuesParser.parse(color_string)
185
+ def parse(value)
186
+ case value
187
+ in ['rgb', args]
188
+ return unless args.length == 3
163
189
 
164
- result = values.map do |value|
165
- case value
166
- in ['rgb', args]
167
- hex = (0..2).collect do |n|
168
- number = args[n].to_f
169
- number *= 2.55 if args[n][-1..] == '%'
190
+ rgb =
191
+ args.map do |arg|
192
+ number = to_float(arg, 2.55) or break
170
193
  format('%02x', number.round.clamp(0, 255))
171
- end.join
172
-
173
- RGB.new(hex)
174
-
175
- in ['device-cmyk', args]
176
- cmyk = (0..3).collect do |n|
177
- number = args[n].to_f
178
- number *= 100 unless args[n][-1..] == '%'
179
- number.clamp(0, 100)
180
194
  end
181
195
 
182
- CMYK.new(cmyk)
196
+ rgb && RGB.new(rgb.join)
197
+
198
+ in ['device-cmyk', args]
199
+ return unless args.length == 4
183
200
 
184
- in ['url', [url]]
185
- url_specified = true
186
- if url[0] == '#' && gradients && (gradient = gradients[url[1..]])
187
- gradient
201
+ cymk =
202
+ args.map do |arg|
203
+ number = to_float(arg, 0.01) or break
204
+ (number * 100).clamp(0, 100)
188
205
  end
189
206
 
190
- in /\A#([0-9a-f])([0-9a-f])([0-9a-f])\z/i
191
- RGB.new("#{$1 * 2}#{$2 * 2}#{$3 * 2}")
207
+ cymk && CMYK.new(cymk)
192
208
 
193
- in /\A#[0-9a-f]{6}\z/i
194
- RGB.new(value[1..])
209
+ in /\A#([0-9a-f])([0-9a-f])([0-9a-f])\z/i
210
+ RGB.new("#{$1 * 2}#{$2 * 2}#{$3 * 2}")
195
211
 
196
- in String => color
197
- if (hex = HTML_COLORS[color.downcase])
198
- hex_color(hex, color_mode)
199
- end
212
+ in /\A#[0-9a-f]{6}\z/i
213
+ RGB.new(value[1..])
200
214
 
201
- else
202
- nil
215
+ in String => color
216
+ if (hex = HTML_COLORS[color.downcase])
217
+ RGB.new(hex)
203
218
  end
204
- end
205
-
206
- # Generally, we default to black if the colour was unparseable.
207
- # http://www.w3.org/TR/SVG/painting.html section 11.2 says if a URL was
208
- # supplied without a fallback, that's an error.
209
- result << default_color(color_mode) unless url_specified
210
219
 
211
- result.compact
212
- end
213
-
214
- def css_color_to_prawn_color(color)
215
- parse(color).detect { |value| value.is_a?(RGB) || value.is_a?(CMYK) }&.value
220
+ else
221
+ nil
222
+ end
216
223
  end
217
224
 
218
225
  def default_color(color_mode)
@@ -221,20 +228,12 @@ class Prawn::SVG::Color
221
228
 
222
229
  private
223
230
 
224
- def hex_color(hex, color_mode)
225
- if color_mode == :cmyk
226
- r, g, b = [hex[0..1], hex[2..3], hex[4..5]].map { |h| h.to_i(16) / 255.0 }
227
- k = 1 - [r, g, b].max
228
- if k == 1
229
- CMYK.new([0, 0, 0, 100])
230
- else
231
- c = (1 - r - k) / (1 - k)
232
- m = (1 - g - k) / (1 - k)
233
- y = (1 - b - k) / (1 - k)
234
- CMYK.new([c, m, y, k].map { |v| (v * 100).round })
235
- end
231
+ def to_float(string, percentage_multiplier)
232
+ if string[-1] == '%'
233
+ number = Float(string[0..-2], exception: false)
234
+ number && (number * percentage_multiplier)
236
235
  else
237
- RGB.new(hex)
236
+ Float(string, exception: false)
238
237
  end
239
238
  end
240
239
  end
@@ -0,0 +1,46 @@
1
+ module Prawn::SVG::CSS
2
+ class FontParser
3
+ def self.parse(string)
4
+ in_quote = nil
5
+ in_escape = false
6
+ in_list_delimiter = false
7
+ current = nil
8
+ values = []
9
+
10
+ string.each_char do |char|
11
+ if in_escape
12
+ in_escape = false
13
+ if current.nil?
14
+ current = char
15
+ values << current
16
+ else
17
+ current << char
18
+ end
19
+ elsif char == ',' && in_quote.nil? && !in_escape && current
20
+ current << char
21
+ in_list_delimiter = true
22
+ elsif char == '\\'
23
+ in_escape = true
24
+ elsif current.nil?
25
+ if char.match(/\s/).nil?
26
+ in_list_delimiter = false
27
+ current = char
28
+ values << current
29
+ end
30
+ elsif !in_quote && !in_escape && !in_list_delimiter && char.match(/\s/)
31
+ current = nil
32
+ else
33
+ current << char
34
+ end
35
+
36
+ if char == in_quote
37
+ in_quote = nil
38
+ elsif in_quote.nil? && ['"', "'"].include?(char)
39
+ in_quote = char
40
+ end
41
+ end
42
+
43
+ values.map(&:rstrip)
44
+ end
45
+ end
46
+ end
@@ -17,7 +17,11 @@ class Prawn::SVG::Document
17
17
  :color_mode
18
18
 
19
19
  def initialize(data, bounds, options, font_registry: nil, css_parser: CssParser::Parser.new, attribute_overrides: {})
20
- @root = REXML::Document.new(data).root
20
+ begin
21
+ @root = REXML::Document.new(data).root
22
+ rescue REXML::ParseException
23
+ @root = nil
24
+ end
21
25
 
22
26
  if @root.nil?
23
27
  if data.respond_to?(:end_with?) && data.end_with?('.svg')
@@ -158,8 +158,8 @@ class Prawn::SVG::Elements::Base
158
158
  def apply_drawing_call
159
159
  return if state.disable_drawing || !drawable?
160
160
 
161
- fill = computed_properties.fill != 'none'
162
- stroke = computed_properties.stroke != 'none'
161
+ fill = !computed_properties.fill.none? # rubocop:disable Style/InverseMethods
162
+ stroke = !computed_properties.stroke.none? # rubocop:disable Style/InverseMethods
163
163
 
164
164
  if fill
165
165
  command = stroke ? 'fill_and_stroke' : 'fill'
@@ -178,31 +178,27 @@ class Prawn::SVG::Elements::Base
178
178
 
179
179
  def apply_colors
180
180
  PAINT_TYPES.each do |type|
181
- color = properties.send(type)
181
+ paint = properties.send(type)
182
182
 
183
- next if [nil, 'inherit', 'none'].include?(color)
183
+ case paint
184
+ when nil, 'inherit'
185
+ next
186
+ when Prawn::SVG::Paint
187
+ color = paint.resolve(document.gradients, computed_properties.color, document.color_mode)
184
188
 
185
- color = computed_properties.color if color == 'currentColor'
186
-
187
- results = Prawn::SVG::Color.parse(color, document.gradients, document.color_mode)
188
-
189
- success = results.detect do |result|
190
- case result
189
+ case color
191
190
  when Prawn::SVG::Color::RGB, Prawn::SVG::Color::CMYK
192
- add_call "#{type}_color", result.value
193
- true
191
+ add_call "#{type}_color", color.value
194
192
  when Prawn::SVG::Elements::Gradient
195
- arguments = result.gradient_arguments(self)
196
- if arguments
197
- add_call "#{type}_gradient", **arguments
198
- true
199
- end
193
+ add_call 'svg:render_gradient', type.to_sym, **color.gradient_arguments(self)
194
+ when nil
195
+ nil
196
+ else
197
+ raise "Unknown resolved color type: #{color.inspect}"
200
198
  end
199
+ else
200
+ raise "Unknown paint type: #{paint.inspect}"
201
201
  end
202
-
203
- # If we were unable to find a suitable color candidate,
204
- # we turn off this type of paint.
205
- computed_properties.set(type, 'none') if success.nil?
206
202
  end
207
203
  end
208
204
 
@@ -250,15 +246,11 @@ class Prawn::SVG::Elements::Base
250
246
  end
251
247
  end
252
248
 
253
- def extract_element_from_url_id_reference(values, expected_type = nil)
254
- Prawn::SVG::CSS::ValuesParser.parse(values).detect do |value|
255
- case value
256
- in ['url', [url]]
257
- element = document.elements_by_id[url[1..]] if url.start_with?('#')
258
- break element if element && (expected_type.nil? || element.name == expected_type)
259
- else
260
- nil
261
- end
249
+ def extract_element_from_url_id_reference(value, expected_type = nil)
250
+ case value
251
+ when Prawn::SVG::FuncIRI
252
+ element = document.elements_by_id[value.url[1..]] if value.url.start_with?('#')
253
+ element if element && (expected_type.nil? || element.name == expected_type)
262
254
  end
263
255
  end
264
256