lib/prawn/font/afm.rb in prawn-2.1.0 vs lib/prawn/font/afm.rb in prawn-2.2.0
- old
+ new
@@ -1,14 +1,12 @@
-# encoding: utf-8
-
# prawn/font/afm.rb : Implements AFM font support for Prawn
#
# Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
#
# This is free software. Please see the LICENSE and COPYING files for details.
-require_relative "../encoding"
+require_relative '../encoding'
module Prawn
class Font
# @private
@@ -17,58 +15,63 @@
attr_accessor :hide_m17n_warning
end
self.hide_m17n_warning = false
- BUILT_INS = %w[ Courier Helvetica Times-Roman Symbol ZapfDingbats
- Courier-Bold Courier-Oblique Courier-BoldOblique
- Times-Bold Times-Italic Times-BoldItalic
- Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique ]
+ BUILT_INS = %w[
+ Courier Helvetica Times-Roman Symbol ZapfDingbats
+ Courier-Bold Courier-Oblique Courier-BoldOblique
+ Times-Bold Times-Italic Times-BoldItalic
+ Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique
+ ].freeze
def unicode?
false
end
def self.metrics_path
- if m = ENV['METRICS']
- @metrics_path ||= m.split(':')
- else
- @metrics_path ||= [
- ".", "/usr/lib/afm",
- "/usr/local/lib/afm",
- "/usr/openwin/lib/fonts/afm",
- Prawn::DATADIR + '/fonts'
- ]
- end
+ @metrics_path ||= if ENV['METRICS']
+ ENV['METRICS'].split(':')
+ else
+ [
+ '.', '/usr/lib/afm',
+ '/usr/local/lib/afm',
+ '/usr/openwin/lib/fonts/afm',
+ Prawn::DATADIR + '/fonts'
+ ]
+ end
end
attr_reader :attributes #:nodoc:
+ # parse each ATM font file once only
+ def self.font_data
+ @font_data ||= SynchronizedCache.new
+ end
+
def initialize(document, name, options = {}) #:nodoc:
unless BUILT_INS.include?(name)
- fail Prawn::Errors::UnknownFont, "#{name} is not a known font."
+ raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
end
super
- @@font_data ||= SynchronizedCache.new # parse each ATM font file once only
-
file_name = @name.dup
- file_name << ".afm" unless file_name =~ /\.afm$/
+ file_name << '.afm' unless file_name =~ /\.afm$/
file_name = file_name[0] == '/' ? file_name : find_font(file_name)
- font_data = @@font_data[file_name] ||= parse_afm(file_name)
- @glyph_widths = font_data[:glyph_widths]
- @glyph_table = font_data[:glyph_table]
- @bounding_boxes = font_data[:bounding_boxes]
- @kern_pairs = font_data[:kern_pairs]
+ font_data = self.class.font_data[file_name] ||= parse_afm(file_name)
+ @glyph_widths = font_data[:glyph_widths]
+ @glyph_table = font_data[:glyph_table]
+ @bounding_boxes = font_data[:bounding_boxes]
+ @kern_pairs = font_data[:kern_pairs]
@kern_pair_table = font_data[:kern_pair_table]
- @attributes = font_data[:attributes]
+ @attributes = font_data[:attributes]
- @ascender = @attributes["ascender"].to_i
- @descender = @attributes["descender"].to_i
- @line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
+ @ascender = @attributes['ascender'].to_i
+ @descender = @attributes['descender'].to_i
+ @line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
end
# The font bbox, as an array of integers
#
def bbox
@@ -79,11 +82,11 @@
def compute_width_of(string, options = {}) #:nodoc:
scale = (options[:size] || size) / 1000.0
if options[:kerning]
strings, numbers = kern(string).partition { |e| e.is_a?(String) }
- total_kerning_offset = numbers.inject(0.0) { |s, r| s + r }
+ total_kerning_offset = numbers.inject(0.0) { |a, e| a + e }
(unscaled_width_of(strings.join) - total_kerning_offset) * scale
else
unscaled_width_of(string) * scale
end
end
@@ -97,21 +100,23 @@
# built-in fonts only work with winansi encoding, so translate the
# string. Changes the encoding in-place, so the argument itself
# is replaced with a string in WinAnsi encoding.
#
def normalize_encoding(text)
- text.encode("windows-1252")
+ text.encode('windows-1252')
rescue ::Encoding::InvalidByteSequenceError,
::Encoding::UndefinedConversionError
raise Prawn::Errors::IncompatibleStringEncoding,
- "Your document includes text that's not compatible with the Windows-1252 character set.\n" \
- "If you need full UTF-8 support, use TTF fonts instead of PDF's built-in fonts\n."
+ "Your document includes text that's not compatible with the " \
+ "Windows-1252 character set.\n" \
+ "If you need full UTF-8 support, use TTF fonts instead of PDF's " \
+ "built-in fonts.\n"
end
def to_utf8(text)
- text.encode("UTF-8")
+ text.encode('UTF-8')
end
# Returns the number of characters in +str+ (a WinAnsi-encoded string).
#
def character_count(str)
@@ -133,67 +138,75 @@
def encode_text(text, options = {})
[[0, options[:kerning] ? kern(text) : text]]
end
def glyph_present?(char)
- !!normalize_encoding(char)
+ !normalize_encoding(char).nil?
rescue Prawn::Errors::IncompatibleStringEncoding
false
end
private
- def register(subset)
+ def register(_subset)
font_dict = {
- :Type => :Font,
- :Subtype => :Type1,
- :BaseFont => name.to_sym
+ Type: :Font,
+ Subtype: :Type1,
+ BaseFont: name.to_sym
}
# Symbolic AFM fonts (Symbol, ZapfDingbats) have their own encodings
- font_dict.merge!(:Encoding => :WinAnsiEncoding) unless symbolic?
+ font_dict[:Encoding] = :WinAnsiEncoding unless symbolic?
@document.ref!(font_dict)
end
def symbolic?
- attributes["characterset"] == "Special"
+ attributes['characterset'] == 'Special'
end
def find_font(file)
- self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } + "/#{file}"
+ self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
+ "/#{file}"
rescue NoMethodError
raise Prawn::Errors::UnknownFont,
- "Couldn't find the font: #{file} in any of:\n" + self.class.metrics_path.join("\n")
+ "Couldn't find the font: #{file} in any of:\n" +
+ self.class.metrics_path.join("\n")
end
def parse_afm(file_name)
- data = { :glyph_widths => {}, :bounding_boxes => {}, :kern_pairs => {}, :attributes => {} }
+ data = {
+ glyph_widths: {},
+ bounding_boxes: {},
+ kern_pairs: {},
+ attributes: {}
+ }
section = []
File.foreach(file_name) do |line|
case line
when /^Start(\w+)/
- section.push $1
+ section.push Regexp.last_match(1)
next
when /^End(\w+)/
section.pop
next
end
case section
- when ["FontMetrics", "CharMetrics"]
+ when %w[FontMetrics CharMetrics]
next unless line =~ /^CH?\s/
- name = line[/\bN\s+(\.?\w+)\s*;/, 1]
- data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
+ name = line[/\bN\s+(\.?\w+)\s*;/, 1]
+ data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
data[:bounding_boxes][name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
- when ["FontMetrics", "KernData", "KernPairs"]
+ when %w[FontMetrics KernData KernPairs]
next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
- data[:kern_pairs][[$1, $2]] = $3.to_i
- when ["FontMetrics", "KernData", "TrackKern"],
- ["FontMetrics", "Composites"]
+ data[:kern_pairs][[Regexp.last_match(1), Regexp.last_match(2)]] =
+ Regexp.last_match(3).to_i
+ when %w[FontMetrics KernData TrackKern],
+ %w[FontMetrics Composites]
next
else
parse_generic_afm_attribute(line, data)
end
end
@@ -202,24 +215,35 @@
# will be used when measuring and kerning text
data[:glyph_table] = (0..255).map do |i|
data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
end
- character_hash = Hash[Encoding::WinAnsi::CHARACTERS.zip((0..Encoding::WinAnsi::CHARACTERS.size).to_a)]
- data[:kern_pair_table] = data[:kern_pairs].each_with_object({}) do |p, h|
- h[p[0].map { |n| character_hash[n] }] = p[1]
- end
+ character_hash = Hash[
+ Encoding::WinAnsi::CHARACTERS.zip(
+ (0..Encoding::WinAnsi::CHARACTERS.size).to_a
+ )
+ ]
+ data[:kern_pair_table] =
+ data[:kern_pairs].each_with_object({}) do |p, h|
+ h[p[0].map { |n| character_hash[n] }] = p[1]
+ end
data.each_value(&:freeze)
data.freeze
end
def parse_generic_afm_attribute(line, hash)
line =~ /(^\w+)\s+(.*)/
- key, value = $1.to_s.downcase, $2
+ key = Regexp.last_match(1).to_s.downcase
+ value = Regexp.last_match(2)
- hash[:attributes][key] = hash[:attributes][key] ? Array(hash[:attributes][key]) << value : value
+ hash[:attributes][key] =
+ if hash[:attributes][key]
+ Array(hash[:attributes][key]) << value
+ else
+ value
+ end
end
# converts a string into an array with spacing offsets
# bewteen characters that need to be kerned
#
@@ -228,24 +252,27 @@
def kern(string)
kerned = [[]]
last_byte = nil
string.each_byte do |byte|
- if k = last_byte && @kern_pair_table[[last_byte, byte]]
+ k = last_byte && @kern_pair_table[[last_byte, byte]]
+ if k
kerned << -k << [byte]
else
kerned.last << byte
end
last_byte = byte
end
- kerned.map { |e|
- e = (Array === e ? e.pack("C*") : e)
- e.respond_to?(:force_encoding) ? e.force_encoding(::Encoding::Windows_1252) : e
- }
+ kerned.map do |e|
+ e = e.is_a?(Array) ? e.pack('C*') : e
+ if e.respond_to?(:force_encoding)
+ e.force_encoding(::Encoding::Windows_1252)
+ else
+ e
+ end
+ end
end
-
- private
def unscaled_width_of(string)
string.bytes.inject(0) do |s, r|
s + @glyph_table[r]
end