diff --git a/lib/prawn/svg/elements.rb b/lib/prawn/svg/elements.rb index 123c14e..33313ad 100644 --- a/lib/prawn/svg/elements.rb +++ b/lib/prawn/svg/elements.rb @@ -2,6 +2,8 @@ module Prawn::SVG::Elements COMMA_WSP_REGEXP = /(?:\s+,?\s*|,\s*)/ end +require 'prawn/svg/elements/call_duplicator' + %w(base depth_first_base root container viewport style text text_component line polyline polygon circle ellipse rect path use image gradient marker ignored).each do |filename| require "prawn/svg/elements/#{filename}" end diff --git a/lib/prawn/svg/elements/base.rb b/lib/prawn/svg/elements/base.rb index 3e6f77e..7a189e3 100644 --- a/lib/prawn/svg/elements/base.rb +++ b/lib/prawn/svg/elements/base.rb @@ -1,6 +1,8 @@ class Prawn::SVG::Elements::Base extend Forwardable + include Prawn::SVG::Elements::CallDuplicator + include Prawn::SVG::Calculators::Pixels include Prawn::SVG::Attributes::Transform @@ -106,7 +108,7 @@ def append_calls_to_parent end def add_calls_from_element(other) - @calls.concat other.base_calls + @calls.concat duplicate_calls(other.base_calls) end def new_call_context_from_base diff --git a/lib/prawn/svg/elements/call_duplicator.rb b/lib/prawn/svg/elements/call_duplicator.rb new file mode 100644 index 0000000..9e0926a --- /dev/null +++ b/lib/prawn/svg/elements/call_duplicator.rb @@ -0,0 +1,37 @@ +# +# Unfortunately, prawn mutates arguments passed in to it. +# When we make a copy of one of the call stacks, we need to make a deep +# duplicate of it so that the first time prawn mutates the arguments, it +# won't affect the subsequent calls. +# +module Prawn::SVG::Elements::CallDuplicator + private + + def duplicate_calls(calls) + calls.map { |call| duplicate_call(call) } + end + + def duplicate_call(call) + [call[0], duplicate_array(call[1]), duplicate_calls(call[2])] + end + + def duplicate_array(array) + array.map do |value| + case value + when Array then duplicate_array(value) + when Hash then duplicate_hash(value) + else value + end + end + end + + def duplicate_hash(hash) + hash.each.with_object({}) do |(key, value), result| + result[key] = case value + when Array then duplicate_array(value) + when Hash then duplicate_hash(value) + else value + end + end + end +end