diff --git a/data/fonts/Bodoni-Book.otf b/data/fonts/Bodoni-Book.otf new file mode 100644 index 000000000..a4e55f903 Binary files /dev/null and b/data/fonts/Bodoni-Book.otf differ diff --git a/lib/prawn/font.rb b/lib/prawn/font.rb index b9ca085c3..22bf7a475 100644 --- a/lib/prawn/font.rb +++ b/lib/prawn/font.rb @@ -282,6 +282,7 @@ class Font require_relative 'fonts/afm' require_relative 'fonts/ttf' require_relative 'fonts/dfont' + require_relative 'fonts/otf' require_relative 'fonts/ttc' # @deprecated @@ -305,9 +306,10 @@ class Font # Fonts::AFM.new() def self.load(document, src, options = {}) case font_format(src, options) - when 'ttf' then TTF.new(document, src, options) + when 'ttf' then TTF.new(document, src, options) + when 'otf' then Fonts::OTF.new(document, src, options) when 'dfont' then DFont.new(document, src, options) - when 'ttc' then TTC.new(document, src, options) + when 'ttc' then TTC.new(document, src, options) else AFM.new(document, src, options) end end @@ -317,6 +319,7 @@ def self.font_format(src, options) case src.to_s when /\.ttf$/i then 'ttf' + when /\.otf$/i then 'otf' when /\.dfont$/i then 'dfont' when /\.ttc$/i then 'ttc' else 'afm' diff --git a/lib/prawn/fonts/afm.rb b/lib/prawn/fonts/afm.rb index aedbbca67..1cf67efb8 100644 --- a/lib/prawn/fonts/afm.rb +++ b/lib/prawn/fonts/afm.rb @@ -97,9 +97,11 @@ def compute_width_of(string, options = {}) #:nodoc: # Returns true if the font has kerning data, false otherwise # + # rubocop: disable Naming/PredicateName def has_kerning_data? @kern_pairs.any? end + # rubocop: enable Naming/PredicateName # built-in fonts only work with winansi encoding, so translate the # string. Changes the encoding in-place, so the argument itself @@ -113,8 +115,8 @@ def normalize_encoding(text) 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 external fonts instead of PDF's " \ - "built-in fonts.\n" + 'If you need full UTF-8 support, use external fonts instead of ' \ + "PDF's built-in fonts.\n" end def to_utf8(text) diff --git a/lib/prawn/fonts/otf.rb b/lib/prawn/fonts/otf.rb new file mode 100644 index 000000000..6257d345c --- /dev/null +++ b/lib/prawn/fonts/otf.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require_relative 'ttf' + +module Prawn + module Fonts + # @private + class OTF < TTF + end + end +end diff --git a/lib/prawn/fonts/ttf.rb b/lib/prawn/fonts/ttf.rb index 9ebc792c8..7a1819df8 100644 --- a/lib/prawn/fonts/ttf.rb +++ b/lib/prawn/fonts/ttf.rb @@ -62,9 +62,12 @@ def bbox end # Returns true if the font has kerning data, false otherwise + # + # rubocop: disable Naming/PredicateName def has_kerning_data? @has_kerning_data end + # rubocop: enable Naming/PredicateName # Perform any changes to the string that need to happen # before it is rendered to the canvas. Returns an array of diff --git a/lib/prawn/text.rb b/lib/prawn/text.rb index 62ce1f8ed..638f58059 100644 --- a/lib/prawn/text.rb +++ b/lib/prawn/text.rb @@ -294,7 +294,7 @@ def draw_text!(text, options) unless font.unicode? || font.class.hide_m17n_warning || text.ascii_only? warn "PDF's built-in fonts have very limited support for " \ "internationalized text.\nIf you need full UTF-8 support, " \ - "consider using a TTF font instead.\n\nTo disable this " \ + "consider using an external font instead.\n\nTo disable this " \ "warning, add the following line to your code:\n" \ "Prawn::Fonts::AFM.hide_m17n_warning = true\n" diff --git a/lib/prawn/text/box.rb b/lib/prawn/text/box.rb index ecbeaeeeb..ccdc1ed33 100644 --- a/lib/prawn/text/box.rb +++ b/lib/prawn/text/box.rb @@ -61,7 +61,7 @@ module Text # or right-to-left) [value of document.text_direction] # :fallback_fonts:: # An array of font names. Each name must be the name of an AFM font or - # the name that was used to register a family of TTF fonts (see + # the name that was used to register a family of external fonts (see # Prawn::Document#font_families). If present, then each glyph will be # rendered using the first font that includes the glyph, starting with # the current font and then moving through :fallback_fonts from diff --git a/manual/text/line_wrapping.rb b/manual/text/line_wrapping.rb index cf6c1883c..2357d87d3 100644 --- a/manual/text/line_wrapping.rb +++ b/manual/text/line_wrapping.rb @@ -5,7 +5,8 @@ # display space without allowing for a break. # # For writing styles that do not make use of spaces, the zero width space serves -# to mark word boundaries. Zero width spaces are available only with TTF fonts. +# to mark word boundaries. Zero width spaces are available only with external +# fonts. require_relative '../example_helper' diff --git a/manual/text/registering_families.rb b/manual/text/registering_families.rb index bb891018c..b1f99f25e 100644 --- a/manual/text/registering_families.rb +++ b/manual/text/registering_families.rb @@ -12,7 +12,7 @@ filename = File.basename(__FILE__).gsub('.rb', '.pdf') Prawn::ManualBuilder::Example.generate(filename) do - # Registering a single TTF font + # Registering a single external font font_families.update( 'DejaVu Sans' => { normal: "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf" diff --git a/manual/text/utf8.rb b/manual/text/utf8.rb index d7fbd1037..348f64e07 100644 --- a/manual/text/utf8.rb +++ b/manual/text/utf8.rb @@ -17,7 +17,7 @@ move_down 20 - text 'For full internationalized text support, we need to use TTF fonts:' + text 'For full internationalized text support, we need to use external fonts:' move_down 20 font("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf") do diff --git a/prawn.gemspec b/prawn.gemspec index 0d78f984c..b8dbe51a9 100644 --- a/prawn.gemspec +++ b/prawn.gemspec @@ -37,7 +37,7 @@ Gem::Specification.new do |spec| spec.licenses = %w[PRAWN GPL-2.0 GPL-3.0] spec.add_dependency('pdf-core', '~> 0.8.1') - spec.add_dependency('ttfunk', '~> 1.5') + spec.add_dependency('ttfunk', '~> 1.6') spec.add_development_dependency('pdf-inspector', '>= 1.2.1', '< 2.0.a') spec.add_development_dependency('pdf-reader', ['~> 1.4', '>= 1.4.1']) diff --git a/spec/prawn/font_spec.rb b/spec/prawn/font_spec.rb index f654e305f..0df17f3a9 100644 --- a/spec/prawn/font_spec.rb +++ b/spec/prawn/font_spec.rb @@ -457,6 +457,37 @@ def page_should_not_include_font(font) end end + describe 'OTF fonts' do + let(:font) { pdf.find_font "#{Prawn::DATADIR}/fonts/Bodoni-Book.otf" } + + it 'calculates string width taking into account accented characters' do + expect(font.compute_width_of('é', size: 12)).to eq( + font.compute_width_of('e', size: 12) + ) + end + + it 'uses the ascender, descender, and cap height from the OTF verbatim' do + # These metrics are relative to the font's own bbox. They should not be + # scaled with font size. + ref = pdf.ref!({}) + font.send :embed, ref, 0 + + # Pull out the embedded font descriptor + descriptor = ref.data[:FontDescriptor].data + expect(descriptor[:Ascent]).to eq(1023) + expect(descriptor[:Descent]).to eq(-200) + expect(descriptor[:CapHeight]).to eq(3072) + end + + describe 'when normalizing encoding' do + it 'does not modify the original string with normalize_encoding()' do + original = 'Foo' + normalized = font.normalize_encoding(original) + expect(original).to_not be_equal(normalized) + end + end + end + describe 'DFont fonts' do let(:file) { "#{Prawn::DATADIR}/fonts/Panic+Sans.dfont" } diff --git a/spec/prawn_manual_spec.rb b/spec/prawn_manual_spec.rb index 1f1c6e8a0..4f66897a3 100644 --- a/spec/prawn_manual_spec.rb +++ b/spec/prawn_manual_spec.rb @@ -6,11 +6,11 @@ MANUAL_HASH = case RUBY_ENGINE when 'ruby' - '85d2ded146d1e6659e9db389a071896d6e57d7cc4210c6b7fc75fc4afe2b5697'\ - '8a86baca785acd717964619dc234327ef59f5ba6d750dfd626279af0166f6c5e' + 'b38bd8aaa7b419a2f594ee8837cd62f813141000393995b0c0456644b823a62a'\ + '2f8031b2db0fc9e7c544b3946a9b0e60570d510564e6fed3931e0717dd49188a' when 'jruby' - '85d2ded146d1e6659e9db389a071896d6e57d7cc4210c6b7fc75fc4afe2b5697'\ - '8a86baca785acd717964619dc234327ef59f5ba6d750dfd626279af0166f6c5e' + 'b38bd8aaa7b419a2f594ee8837cd62f813141000393995b0c0456644b823a62a'\ + '2f8031b2db0fc9e7c544b3946a9b0e60570d510564e6fed3931e0717dd49188a' end RSpec.describe Prawn do