lib/prawn/svg/parser.rb in prawn-svg-0.12.0.3 vs lib/prawn/svg/parser.rb in prawn-svg-0.12.0.4
- old
+ new
@@ -10,16 +10,16 @@
# This class is not passed the prawn object, so knows nothing about
# prawn specifically - this might be useful if you want to take this code and use it to convert
# SVG to another format.
#
class Prawn::Svg::Parser
- CONTAINER_TAGS = %w(g svg symbol defs)
-
+ CONTAINER_TAGS = %w(g svg symbol defs clipPath)
+
#
- # Construct a Parser object.
+ # Construct a Parser object.
#
- # The +data+ argument is SVG data.
+ # The +data+ argument is SVG data.
#
# +bounds+ is a tuple [width, height] that specifies the bounds of the drawing space in points.
#
# +options+ can optionally contain
# the key :width or :height. If both are specified, only :width will be used.
@@ -38,50 +38,51 @@
# ]
# ]
#
def parse
@document.warnings.clear
-
+
calls = [['fill_color', '000000', []]]
root_element = Prawn::Svg::Element.new(@document, @document.root, calls, :ids => {}, :fill => true)
-
+
parse_element(root_element)
calls
end
- private
+ private
REQUIRED_ATTRIBUTES = {
"polyline" => %w(points),
"polygon" => %w(points),
"circle" => %w(r),
"ellipse" => %w(rx ry),
"rect" => %w(width height),
"path" => %w(d),
- "image" => %w(width height)
+ "image" => %w(width height)
}
-
+
USE_NEW_CIRCLE_CALL = Prawn::Document.new.respond_to?(:circle)
USE_NEW_ELLIPSE_CALL = Prawn::Document.new.respond_to?(:ellipse)
def parse_element(element)
attrs = element.attributes
if required_attributes = REQUIRED_ATTRIBUTES[element.name]
return unless check_attrs_present(element, required_attributes)
end
-
+
case element.name
when *CONTAINER_TAGS
+ do_not_append_calls = %w(symbol defs clipPath).include?(element.name)
+ element.state[:disable_drawing] = true if element.name == "clipPath"
+
element.each_child_element do |child|
element.add_call "save"
parse_element(child)
element.add_call "restore"
end
-
- do_not_append_calls = %w(symbol defs).include?(element.name)
-
+
when 'style'
load_css_styles(element)
when 'text'
@svg_text ||= Text.new
@@ -105,60 +106,60 @@
points = attrs['points'].split(/\s+/).collect do |point|
x, y = point.split(",")
[x(x), y(y)]
end
element.add_call "polygon", *points
-
+
when 'circle'
if USE_NEW_CIRCLE_CALL
- element.add_call "circle",
+ element.add_call "circle",
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['r'])
else
- element.add_call "circle_at",
+ element.add_call "circle_at",
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], :radius => distance(attrs['r'])
end
-
+
when 'ellipse'
- element.add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at",
+ element.add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at",
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['rx']), distance(attrs['ry'])
-
+
when 'rect'
radius = distance(attrs['rx'] || attrs['ry'])
args = [[x(attrs['x'] || '0'), y(attrs['y'] || '0')], distance(attrs['width']), distance(attrs['height'])]
if radius
# n.b. does not support both rx and ry being specified with different values
element.add_call "rounded_rectangle", *(args + [radius])
else
element.add_call "rectangle", *args
end
-
+
when 'path'
parse_path(element)
-
+
when 'use'
parse_use(element)
when 'title', 'desc', 'metadata'
# ignore
do_not_append_calls = true
-
- when 'font-face', 'clipPath'
+
+ when 'font-face'
# not supported
do_not_append_calls = true
when 'image'
@svg_image ||= Image.new(@document)
@svg_image.parse(element)
else
@document.warnings << "Unknown tag '#{element.name}'; ignoring"
end
-
+
element.append_calls_to_parent unless do_not_append_calls
end
-
+
def parse_path(element)
@svg_path ||= Path.new
begin
commands = @svg_path.parse(element.attributes['d'])
@@ -177,35 +178,34 @@
end
element.add_call command, point_to, opts
else
element.add_call command
end
- end
+ end
end
-
+
def parse_use(element)
if href = element.attributes['xlink:href']
if href[0..0] == '#'
id = href[1..-1]
- if id_calls = element.state[:ids][id]
+ if definition_element = @document.elements_by_id[id]
x = element.attributes['x']
y = element.attributes['y']
if x || y
element.add_call_and_enter "translate", distance(x || 0), -distance(y || 0)
end
-
- element.calls.concat(id_calls)
+ element.add_calls_from_element definition_element
else
@document.warnings << "no tag with ID '#{id}' was found, referenced by use tag"
end
else
@document.warnings << "use tag has an href that is not a reference to an id; this is not supported"
end
else
@document.warnings << "no xlink:href specified on use tag"
end
- end
+ end
####################################################################################################################
def load_css_styles(element)
if @document.css_parser
@@ -213,21 +213,21 @@
element.element.cdatas.collect {|d| d.to_s}.join
else
element.element.text
end
- @document.css_parser.add_block!(data)
- end
+ @document.css_parser.add_block!(data)
+ end
end
def check_attrs_present(element, attrs)
missing_attrs = attrs - element.attributes.keys
if missing_attrs.any?
@document.warnings << "Must have attributes #{missing_attrs.join(", ")} on tag #{element.name}; skipping tag"
end
missing_attrs.empty?
end
-
+
%w(x y distance).each do |method|
define_method(method) {|*a| @document.send(method, *a)}
end
end