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