From fd18ed2a65722cb962bef111af6a7f5f4b310d46 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Mon, 22 Jan 2024 17:43:55 +0200 Subject: [PATCH 1/2] Test case for wrong width of missing glyphs --- spec/prawn/font_spec.rb | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/spec/prawn/font_spec.rb b/spec/prawn/font_spec.rb index a890c907e..ac9da98f4 100644 --- a/spec/prawn/font_spec.rb +++ b/spec/prawn/font_spec.rb @@ -670,4 +670,43 @@ def page_should_not_include_font(font) font_name = text.font_settings.first[:name].to_s.sub(/\w+\+/, 'subset+') expect(font_name).to eq 'subset+DustismoRoman' end + + it 'does not change width of unknown glyph' do + text_with_string_widths = + Class.new(PDF::Inspector::Text) do + attr_reader :string_widths + + def initialize(*) + super + @string_widths = [] + end + + def show_text(text, kerned = false) + super + @string_widths << ((@state.current_font.unpack text).reduce(0) do |width, code| + width + (@state.current_font.glyph_width code) * @font_settings[-1][:size] / 1000.0 + end) + end + end + + pdf = + Prawn::Document.new do + font_families.update( + 'DejaVu Sans' => { + normal: "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf", + bold: "#{Prawn::DATADIR}/fonts/DejaVuSans-Bold.ttf" + } + ) + + # changing option to subset: false fixes issue (albeit using different behavior) + font 'DejaVu Sans', subset: true do + text '日本語end', inline_format: true + end + end + + rendered_pdf = pdf.render + analyzed_pdf = text_with_string_widths.analyze(rendered_pdf) + expect(analyzed_pdf.string_widths.length).to be 2 + expect(analyzed_pdf.string_widths[0]).to be > 0.0 + end end From b5017b87b9c72433302e5cf1718f56b06e4ce0c8 Mon Sep 17 00:00:00 2001 From: Alexander Mankuta Date: Mon, 22 Jan 2024 17:46:50 +0200 Subject: [PATCH 2/2] Fix missing glyph width. Prawn correctly used width of missing glyphs to layout text but didn't encode the widths correctly in subset fonts. The resulted in characters with missing glyphs to have 0 width. And even though Prawn drawn Replacement Character glyphs they were stacking on top of each other because their widths were wrong. --- lib/prawn/fonts/ttf.rb | 12 ++++++------ spec/prawn_manual_spec.rb | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/prawn/fonts/ttf.rb b/lib/prawn/fonts/ttf.rb index 5e55220f9..779234de8 100644 --- a/lib/prawn/fonts/ttf.rb +++ b/lib/prawn/fonts/ttf.rb @@ -393,18 +393,18 @@ def embed_simple_font(reference, font, unicode_mapping) XHeight: x_height ) - first_char = font.cmap.tables.first.code_map.index { |gid| !gid.zero? } - last_char = font.cmap.tables.first.code_map.rindex { |gid| !gid.zero? } + first_char, last_char = unicode_mapping.keys.minmax hmtx = font.horizontal_metrics widths = - font.cmap.tables.first.code_map[first_char..last_char].map do |gid| - if gid.zero? + (first_char..last_char).map do |code| + if unicode_mapping.key?(code) + gid = font.cmap.tables.first.code_map[code] + Integer(hmtx.widths[gid] * scale_factor) + else # These characters are not in the document so we don't ever use # these values but we need to encode them so let's use as little # sapce as possible. 0 - else - Integer(hmtx.widths[gid] * scale_factor) end end diff --git a/spec/prawn_manual_spec.rb b/spec/prawn_manual_spec.rb index b92c55441..105016409 100644 --- a/spec/prawn_manual_spec.rb +++ b/spec/prawn_manual_spec.rb @@ -6,9 +6,9 @@ MANUAL_HASH = case RUBY_ENGINE when 'ruby' - '8ace5f35f945e5994647cefc2cf7bc369d131e0646d91eb8aeb94e58f72de18d8e7bf82f58fc45406110c4adad239dcbe834059580d29fec2b2a039db67db04c' + '7991e4f72e944140840e1c26f0fff331029846eaab148de8483d06491c7808bc4963e8e7376a514e855037f1f1b4197877a31f2df44f511f4f7f5e0ce5df3170' when 'jruby' - 'b77a740d3290192360c4c083018ca61ccc88d42e7c6a152c7bc394d751f5f08d85aec613549f6660713644b00518561cc0f9c947701f01e8c25632c9db81201a' + '29b8f8cb00910426805ce226fb47c59d6409683f35f0d2c056a6cf837ba086ca5c763ff89266cfc8e11b1d92af60c9974822b12ad761cdbdf520adb005a98750' end RSpec.describe Prawn do