class Prawn::SVG::Elements::Text < Prawn::SVG::Elements::DepthFirstBase private # This class doesn't represent an element in the SVG document; it's here # to hold together text information. Because of this, we overload the # parse_step and apply_step methods, and bypass all the normal processing # of the element, delegating it to our root text component. def parse_step state.text = Prawn::SVG::Elements::TextComponent::TextState.new @text_root = Prawn::SVG::Elements::TextComponent.new(document, source, nil, state.dup) @text_root.parse_step reintroduce_trailing_and_leading_whitespace end def apply_step(calls) @base_calls = @calls = calls add_call_and_enter 'text_group' @text_root.apply_step(@calls) end def drawable? false end def reintroduce_trailing_and_leading_whitespace printables = [] built_printable_queue(printables, @text_root) remove_whitespace_only_printables_and_start_and_end(printables) remove_printables_that_are_completely_empty(printables) apportion_leading_and_trailing_spaces(printables) end def built_printable_queue(queue, component) component.commands.each do |command| case command when Prawn::SVG::Elements::TextComponent::Printable queue << command else built_printable_queue(queue, command) end end end def remove_whitespace_only_printables_and_start_and_end(printables) printables.pop while printables.last && printables.last.text.empty? printables.shift while printables.first && printables.first.text.empty? end def remove_printables_that_are_completely_empty(printables) printables.reject! do |printable| printable.text.empty? && !printable.trailing_space? && !printable.leading_space? end end def apportion_leading_and_trailing_spaces(printables) printables.each_cons(2) do |a, b| if a.text.empty? # Empty strings can only get a leading space from the previous non-empty text, # and never get a trailing space elsif a.trailing_space? a.text += ' ' elsif b.leading_space? b.text = " #{b.text}" end end end end