lib/prawn/document/text.rb in prawn-0.3.0 vs lib/prawn/document/text.rb in prawn-0.4.0

- old
+ new

@@ -5,14 +5,16 @@ # Copyright May 2008, Gregory Brown. All Rights Reserved. # # This is free software. Please see the LICENSE and COPYING files for details. require "zlib" require "prawn/document/text/box" +require "prawn/document/text/wrapping" module Prawn class Document module Text + include Wrapping # Draws text on the page. If a point is specified via the +:at+ # option the text will begin exactly at that point, and the string is # assumed to be pre-formatted to properly fit the page. # @@ -42,30 +44,13 @@ # === Text Positioning Details: # # When using the :at parameter, Prawn will position your text by its # baseline, and flow along a single line. # - # When using automatic text flow, Prawn currently does a bunch of nasty - # hacks to get things to position nicely in bounding boxes, table cells, - # etc. + # Otherwise, the text is positioned at font.ascender below the baseline, + # making it easy to use this method within bounding boxes and spans. # - # For AFM fonts, the first line of text is positioned font.height below - # the baseline. - # - # For TTF fonts, the first line is possitioned font.ascender below the - # baseline. - # - # The issue here is that there are complex issues with determining the - # size of the glyphs above and below the baseline in TTF that we haven't - # figured out yet, and that AFM and TTF appear to handle things very - # differently. - # - # The moral of the story is that if you want reliable font positioning - # for your advanced needs, use :at, otherwise, just let Prawn do its - # positioning magic for you, or investigate and help us get rid of this - # ugly issue. - # # == Rotation # # Text can be rotated before it is placed on the canvas by specifying the # :rotate option. Rotation occurs counter-clockwise. # @@ -85,29 +70,26 @@ def text(text,options={}) # we'll be messing with the strings encoding, don't change the users # original string text = text.to_s.dup - # we might also mess with the font - original_font = font.name - - options = text_options.merge(options) - process_text_options(options) - - font.normalize_encoding(text) unless @skip_encoding + save_font do + options = text_options.merge(options) + process_text_options(options) + + font.normalize_encoding(text) unless @skip_encoding - if options[:at] - x,y = translate(options[:at]) - font.size(options[:size]) { add_text_content(text,x,y,options) } - else - if options[:rotate] - raise ArgumentError, "Rotated text may only be used with :at" - end - wrapped_text(text,options) - end - - font(original_font) + if options[:at] + x,y = translate(options[:at]) + font_size(options[:size]) { add_text_content(text,x,y,options) } + else + if options[:rotate] + raise ArgumentError, "Rotated text may only be used with :at" + end + wrapped_text(text,options) + end + end end # A hash of configuration options, to be used globally by text(). # # pdf.text_options.update(:size => 16, :align => :right) @@ -119,22 +101,22 @@ private def process_text_options(options) Prawn.verify_options [:style, :kerning, :size, :at, :wrap, - :spacing, :align, :rotate ], options + :spacing, :align, :rotate, :final_gap ], options if options[:style] raise "Bad font family" unless font.family font(font.family,:style => options[:style]) end unless options.key?(:kerning) - options[:kerning] = font.metrics.has_kerning_data? + options[:kerning] = font.has_kerning_data? end - options[:size] ||= font.size + options[:size] ||= font_size end def move_text_position(dy) bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom : @bounding_box.absolute_bottom @@ -144,24 +126,21 @@ end def wrapped_text(text,options) options[:align] ||= :left - font.size(options[:size]) do - text = font.metrics.naive_wrap(text, bounds.right, font.size, + font_size(options[:size]) do + text = naive_wrap(text, bounds.right, font_size, :kerning => options[:kerning], :mode => options[:wrap]) lines = text.lines.to_a + last_gap_before = options.fetch(:final_gap, true) ? lines.length : lines.length-1 lines.each_with_index do |e,i| - if font.metrics.type0? - move_text_position(font.ascender) - else - move_text_position(font.height) - end + move_text_position(font.ascender) - line_width = font.width_of(e) + line_width = font.width_of(e, :kerning => options[:kerning]) case(options[:align]) when :left x = @bounding_box.absolute_left when :center x = @bounding_box.absolute_left + @@ -170,33 +149,36 @@ x = @bounding_box.absolute_right - line_width end add_text_content(e,x,y,options) - if font.metrics.type0? && i < lines.length - 1 - move_text_position(font.height - font.ascender) + if i < last_gap_before + move_text_position(font.line_gap - font.descender) + move_text_position(options[:spacing]) if options[:spacing] end - - move_text_position(options[:spacing]) if options[:spacing] end end end def add_text_content(text, x, y, options) - text = font.metrics.convert_text(text,options) + chunks = font.encode_text(text,options) add_content "\nBT" - add_content "/#{font.identifier} #{font.size} Tf" if options[:rotate] rad = options[:rotate].to_i * Math::PI / 180 arr = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ] add_content "%.3f %.3f %.3f %.3f %.3f %.3f Tm" % arr else add_content "#{x} #{y} Td" end - rad = 1.570796 - add_content Prawn::PdfObject(text, true) << - " #{options[:kerning] ? 'TJ' : 'Tj'}" + + chunks.each do |(subset, string)| + font.add_to_current_page(subset) + add_content "/#{font.identifier_for(subset)} #{font_size} Tf" + + operation = options[:kerning] && string.is_a?(Array) ? "TJ" : "Tj" + add_content Prawn::PdfObject(string, true) << " " << operation + end add_content "ET\n" end end end end