diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 627466441..2fad10b0f 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -54,6 +54,7 @@ Bug Fixes:: * decouple tests from path of PWD (#2444) * consider inherited styles when analyzing glyphs for fallback font support (#2463) * add fallback character for placeholder character when using AFM font (#2453) +* don't advance image that's first child of block at top of page if image is taller than page (#2012) == 2.3.9 (2023-06-28) - @mojavelinux diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb index dcec4f988..fcc6ffb94 100644 --- a/lib/asciidoctor/pdf/converter.rb +++ b/lib/asciidoctor/pdf/converter.rb @@ -1819,7 +1819,7 @@ def convert_image node, opts = {} end # NOTE: shrink image so it fits within available space; group image & caption if (rendered_h = svg_size.output_height) > (available_h = cursor - caption_h) - unless pinned || at_page_top? + unless pinned || at_page_top? || (node.first_child? && (node.parent.attr? 'pdf-at-top')) advance_page available_h = cursor - caption_h end @@ -1860,7 +1860,7 @@ def convert_image node, opts = {} rendered_w, rendered_h = image_info.calc_image_dimensions width: (width || [available_w, actual_w].min) # NOTE: shrink image so it fits within available space; group image & caption if rendered_h > (available_h = cursor - caption_h) - unless pinned || at_page_top? + unless pinned || at_page_top? || (node.first_child? && (node.parent.attr? 'pdf-at-top')) advance_page available_h = cursor - caption_h end diff --git a/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb b/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb index daf13c017..fbc175c0e 100644 --- a/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +++ b/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb @@ -13,6 +13,10 @@ def last_child blocks[-1] end + def first_child? + self == parent.blocks[0] + end + def last_child? self == parent.blocks[-1] end diff --git a/lib/asciidoctor/pdf/ext/prawn/extensions.rb b/lib/asciidoctor/pdf/ext/prawn/extensions.rb index c37c4df4f..efae9414f 100644 --- a/lib/asciidoctor/pdf/ext/prawn/extensions.rb +++ b/lib/asciidoctor/pdf/ext/prawn/extensions.rb @@ -990,9 +990,17 @@ def with_dry_run &block # start_new_page. Using start_new_page can mangle the calculation of content block's extent. # def arrange_block node, &block + if at_page_top? + at_top = '' + else + at_top = '' if node.first_child? && (node.parent.attr? 'pdf-at-top') + keep_together = true if node.option? 'unbreakable' + end + node.set_attr 'pdf-at-top', at_top if at_top keep_together = (node.option? 'unbreakable') && !at_page_top? doc = node.document block_for_scratch = proc do + node.set_attr 'pdf-at-top', (at_top = '') if at_page_top? push_scratch doc instance_exec(&block) ensure @@ -1000,6 +1008,8 @@ def arrange_block node, &block end extent = dry_run keep_together: keep_together, onto: [self, keep_together], &block_for_scratch scratch? ? block_for_scratch.call : (yield extent) + ensure + node.remove_attr 'pdf-at-top' if at_top end # This method installs an on_page_create_callback that stops processing if the first page is diff --git a/spec/arrange_block_spec.rb b/spec/arrange_block_spec.rb index bde3cb09d..487dac47b 100644 --- a/spec/arrange_block_spec.rb +++ b/spec/arrange_block_spec.rb @@ -929,8 +929,7 @@ def content (expect image[:y]).to eql 742.0 end - # NOTE: this scenario renders an example block that starts with an empty page - it 'should split block across pages that contains image taller than page at start of block', negative: true do + it 'should split block across pages that contains image taller than page at start of block' do input = <<~'END' ==== image::tall-spacer.png[] @@ -939,18 +938,16 @@ def content pdf = to_pdf input, pdf_theme: pdf_theme, analyze: true images = (to_pdf input, pdf_theme: pdf_theme, analyze: :image).images pages = pdf.pages - (expect pages).to have_size 2 + (expect pages).to have_size 1 page_width, page_height = (get_page_size pdf, 1).map(&:to_f) page_margin = pdf_theme[:page_margin].to_f (expect images).to have_size 1 image = images[0] - (expect image[:page_number]).to be 2 - (expect image[:y]).to eql (page_height - page_margin) - (expect image[:height]).to eql (page_height - page_margin * 2) + (expect image[:page_number]).to be 1 + (expect image[:y]).to eql (page_height - page_margin - 12) + (expect image[:height]).to eql (page_height - 12 - page_margin * 2) p1_gs = (pdf.extract_graphic_states pages[0][:raw_content])[0] (expect p1_gs).to have_background color: 'FFFFCC', top_left: [page_margin, page_height - page_margin], bottom_right: [page_width - page_margin, page_margin] - p2_gs = (pdf.extract_graphic_states pages[1][:raw_content])[0] - (expect p2_gs).to have_background color: 'FFFFCC', top_left: [page_margin, page_height - page_margin], bottom_right: [page_width - page_margin, page_margin] end it 'should split block across pages that contains image taller than page that follows text' do @@ -1350,8 +1347,7 @@ def content (expect image[:y]).to eql 711.009 end - # NOTE: this scenario renders an example block that starts with an empty page - it 'should split block across pages that contains image taller than page at start of block', negative: true do + it 'should split block across pages that contains image taller than page at start of block' do input = <<~'END' before block @@ -1362,19 +1358,17 @@ def content pdf = to_pdf input, pdf_theme: pdf_theme, analyze: true images = (to_pdf input, pdf_theme: pdf_theme, analyze: :image).images pages = pdf.pages - (expect pages).to have_size 3 + (expect pages).to have_size 2 page_width, page_height = (get_page_size pdf, 1).map(&:to_f) page_margin = pdf_theme[:page_margin].to_f (expect images).to have_size 1 image = images[0] - (expect image[:page_number]).to be 3 - (expect image[:y]).to eql (page_height - page_margin) - (expect image[:height]).to eql (page_height - page_margin * 2) + (expect image[:page_number]).to be 2 + (expect image[:y]).to eql (page_height - page_margin - 12) + (expect image[:height]).to eql (page_height - 12 - page_margin * 2) (expect (pdf.extract_graphic_states pages[0][:raw_content])).to be_empty p2_gs = (pdf.extract_graphic_states pages[1][:raw_content])[0] (expect p2_gs).to have_background color: 'FFFFCC', top_left: [page_margin, page_height - page_margin], bottom_right: [page_width - page_margin, page_margin] - p3_gs = (pdf.extract_graphic_states pages[2][:raw_content])[0] - (expect p3_gs).to have_background color: 'FFFFCC', top_left: [page_margin, page_height - page_margin], bottom_right: [page_width - page_margin, page_margin] end # FIXME: this fails when block is unbreakable