lib/prawn/font/ttf.rb in prawn-2.1.0 vs lib/prawn/font/ttf.rb in prawn-2.2.0

- old
+ new

@@ -1,7 +1,5 @@ -# encoding: utf-8 - # prawn/font/ttf.rb : Implements AFM font support for Prawn # # Copyright May 2008, Gregory Brown / James Healy / Jamis Buck # All Rights Reserved. # @@ -21,32 +19,32 @@ end def initialize(document, name, options = {}) super - @ttf = read_ttf_file - @subsets = TTFunk::SubsetCollection.new(@ttf) + @ttf = read_ttf_file + @subsets = TTFunk::SubsetCollection.new(@ttf) - @attributes = {} - @bounding_boxes = {} - @char_widths = {} + @attributes = {} + @bounding_boxes = {} + @char_widths = {} @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any? - @ascender = Integer(@ttf.ascent * scale_factor) - @descender = Integer(@ttf.descent * scale_factor) - @line_gap = Integer(@ttf.line_gap * scale_factor) + @ascender = Integer(@ttf.ascent * scale_factor) + @descender = Integer(@ttf.descent * scale_factor) + @line_gap = Integer(@ttf.line_gap * scale_factor) end # NOTE: +string+ must be UTF8-encoded. def compute_width_of(string, options = {}) #:nodoc: scale = (options[:size] || size) / 1000.0 if options[:kerning] kern(string).inject(0) do |s, r| if r.is_a?(Numeric) s - r else - r.inject(s) { |s2, u| s2 + character_width_by_code(u) } + r.inject(s) { |a, e| a + character_width_by_code(e) } end end * scale else string.codepoints.inject(0) do |s, r| s + character_width_by_code(r) @@ -78,11 +76,13 @@ if options[:kerning] last_subset = nil kern(text).inject([]) do |result, element| if element.is_a?(Numeric) - result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array) + unless result.last[1].is_a?(Array) + result.last[1] = [result.last[1]] + end result.last[1] << element result else encoded = @subsets.encode(element) @@ -98,29 +98,30 @@ result end end end else - @subsets.encode(text.unpack("U*")) + @subsets.encode(text.unpack('U*')) end end def basename @basename ||= @ttf.name.postscript_name end # not sure how to compute this for true-type fonts... - def stemV + def stemV # rubocop: disable Style/MethodName 0 end def italic_angle return @italic_angle if @italic_angle if @ttf.postscript.exists? raw = @ttf.postscript.italic_angle - hi, low = raw >> 16, raw & 0xFF + hi = raw >> 16 + low = raw & 0xFF hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0 @italic_angle = "#{hi}.#{low}".to_f else @italic_angle = 0 end @@ -129,11 +130,11 @@ end def cap_height @cap_height ||= begin height = @ttf.os2.exists? && @ttf.os2.cap_height || 0 - height == 0 ? @ascender : height + height.zero? ? @ascender : height end end def x_height # FIXME: seems like if os2 table doesn't exist, we could @@ -158,28 +159,27 @@ flags = 0 flags |= 0x0001 if @ttf.postscript.fixed_pitch? flags |= 0x0002 if serif? flags |= 0x0008 if script? flags |= 0x0040 if italic_angle != 0 - flags |= 0x0004 # assume the font contains at least some non-latin characters + # Assume the font contains at least some non-latin characters + flags | 0x0004 end end def normalize_encoding(text) - begin - text.encode(::Encoding::UTF_8) - rescue => e - puts e - raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " \ - "#{text.encoding} can not be transparently converted to UTF-8. " \ - "Please ensure the encoding of the string you are attempting " \ - "to use is set correctly" - end + text.encode(::Encoding::UTF_8) + rescue => e + puts e + raise Prawn::Errors::IncompatibleStringEncoding, 'Encoding ' \ + "#{text.encoding} can not be transparently converted to UTF-8. " \ + 'Please ensure the encoding of the string you are attempting ' \ + 'to use is set correctly' end def to_utf8(text) - text.encode("UTF-8") + text.encode('UTF-8') end def glyph_present?(char) code = char.codepoints.first cmap[code] > 0 @@ -192,11 +192,11 @@ end private def cmap - @cmap ||= @ttf.cmap.unicode.first or fail("no unicode cmap for font") + (@cmap ||= @ttf.cmap.unicode.first) || raise('no unicode cmap for font') end # +string+ must be UTF8-encoded. # # Returns an array. If an element is a numeric, it represents the @@ -218,18 +218,18 @@ a end def kern_pairs_table - @kerning_data ||= has_kerning_data? ? @ttf.kerning.tables.first.pairs : {} + @kerning_data ||= + if has_kerning_data? + @ttf.kerning.tables.first.pairs + else + {} + end end - def cid_to_gid_map - max = cmap.code_map.keys.max - (0..max).map { |cid| cmap[cid] }.pack("n*") - end - def hmtx @hmtx ||= @ttf.horizontal_metrics end def character_width_by_code(code) @@ -245,16 +245,16 @@ def scale_factor @scale ||= 1000.0 / @ttf.header.units_per_em end def register(subset) - temp_name = @ttf.name.postscript_name.gsub("\0", "").to_sym - ref = @document.ref!(:Type => :Font, :BaseFont => temp_name) + temp_name = @ttf.name.postscript_name.delete("\0").to_sym + ref = @document.ref!(Type: :Font, BaseFont: temp_name) # Embed the font metrics in the document after everything has been # drawn, just before the document is emitted. - @document.renderer.before_render { |doc| embed(ref, subset) } + @document.renderer.before_render { |_doc| embed(ref, subset) } ref end def embed(reference, subset) @@ -265,33 +265,36 @@ # rather than by parsing the font that the subset produces? font = TTFunk::File.new(font_content) # empirically, it looks like Adobe Reader will not display fonts # if their font name is more than 33 bytes long. Strange. But true. - basename = font.name.postscript_name[0, 33].gsub("\0", "") + basename = font.name.postscript_name[0, 33].delete("\0") - fail "Can't detect a postscript name for #{file}" if basename.nil? + raise "Can't detect a postscript name for #{file}" if basename.nil? - fontfile = @document.ref!(:Length1 => font_content.size) + fontfile = @document.ref!(Length1: font_content.size) fontfile.stream << font_content fontfile.stream.compress! - descriptor = @document.ref!(:Type => :FontDescriptor, - :FontName => basename.to_sym, - :FontFile2 => fontfile, - :FontBBox => bbox, - :Flags => pdf_flags, - :StemV => stemV, - :ItalicAngle => italic_angle, - :Ascent => @ascender, - :Descent => @descender, - :CapHeight => cap_height, - :XHeight => x_height) + descriptor = @document.ref!( + Type: :FontDescriptor, + FontName: basename.to_sym, + FontFile2: fontfile, + FontBBox: bbox, + Flags: pdf_flags, + StemV: stemV, + ItalicAngle: italic_angle, + Ascent: @ascender, + Descent: @descender, + CapHeight: cap_height, + XHeight: x_height + ) hmtx = font.horizontal_metrics - widths = font.cmap.tables.first.code_map.map { |gid| - Integer(hmtx.widths[gid] * scale_factor) }[32..-1] + widths = font.cmap.tables.first.code_map.map do |gid| + Integer(hmtx.widths[gid] * scale_factor) + end[32..-1] # It would be nice to have Encoding set for the macroman subsets, # and only do a ToUnicode cmap for non-encoded unicode subsets. # However, apparently Adobe Reader won't render MacRoman encoded # subsets if original font contains unicode characters. (It has to @@ -302,35 +305,40 @@ # It offends my inner purist, but it'll do. map = @subsets[subset].to_unicode_map ranges = [[]] - map.keys.sort.inject("") do |s, code| + map.keys.sort.inject('') do |_s, code| ranges << [] if ranges.last.length >= 100 unicode = map[code] - ranges.last << "<%02x><%04x>" % [code, unicode] + ranges.last << format('<%02x><%04x>', code, unicode) end - range_blocks = ranges.inject("") do |s, list| - s << "%d beginbfchar\n%s\nendbfchar\n" % [list.length, list.join("\n")] + range_blocks = ranges.inject('') do |s, list| + s << format( + "%d beginbfchar\n%s\nendbfchar\n", + list.length, list.join("\n") + ) end to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip cmap = @document.ref!({}) cmap << to_unicode_cmap cmap.stream.compress! - reference.data.update(:Subtype => :TrueType, - :BaseFont => basename.to_sym, - :FontDescriptor => descriptor, - :FirstChar => 32, - :LastChar => 255, - :Widths => @document.ref!(widths), - :ToUnicode => cmap) + reference.data.update( + Subtype: :TrueType, + BaseFont: basename.to_sym, + FontDescriptor: descriptor, + FirstChar: 32, + LastChar: 255, + Widths: @document.ref!(widths), + ToUnicode: cmap + ) end - UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, "") + UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, '') /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (Adobe)