summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.adoc1
-rw-r--r--lib/asciidoctor/pdf/converter.rb71
-rw-r--r--spec/section_spec.rb40
3 files changed, 80 insertions, 32 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index bbfa8041..2d42fa74 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -68,6 +68,7 @@ Enhancements::
* use Document#authors to retrieve authors instead of extracting the information from the indexed document attributes
* add support for character references that contain both uppercase and lowercase hexadecimal characters (#1990) (*@etiwnad*)
* log error and skip table instead of raising error if cell content cannot fit into column width of table (#2009)
+* extract `arrange_section` method to compute whether section title should be advanced to next page (#2023)
Bug Fixes::
diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb
index d8419b35..5d54debf 100644
--- a/lib/asciidoctor/pdf/converter.rb
+++ b/lib/asciidoctor/pdf/converter.rb
@@ -647,42 +647,36 @@ module Asciidoctor
title, _, subtitle = title.rpartition sep
title = %(#{title}\n<em class="subtitle">#{subtitle}</em>)
end
+ hlevel = sect.level + 1
+ align = (@theme[%(heading_h#{hlevel}_align)] || @theme.heading_align || @base_align).to_sym
chapterlike = !(part = sectname == 'part') && (sectname == 'chapter' || (sect.document.doctype == 'book' && sect.level == 1))
- theme_font :heading, level: (hlevel = sect.level + 1) do
- align = (@theme[%(heading_h#{hlevel}_align)] || @theme.heading_align || @base_align).to_sym
- if part
- unless @theme.heading_part_break_before == 'auto'
- start_new = true
- start_new_part sect
- end
- elsif chapterlike
- if @theme.heading_chapter_break_before != 'auto' ||
- (@theme.heading_part_break_after == 'always' && sect == sect.parent.sections[0])
- start_new = true
- start_new_chapter sect
- end
- end
- unless start_new || at_page_top?
- # FIXME: this height doesn't account for impact of text transform or inline formatting
- heading_height =
- (height_of_typeset_text title, line_height: (@theme[%(heading_h#{hlevel}_line_height)] || @theme.heading_line_height)) +
- (@theme[%(heading_h#{hlevel}_margin_top)] || @theme.heading_margin_top) +
- (@theme[%(heading_h#{hlevel}_margin_bottom)] || @theme.heading_margin_bottom)
- heading_height += @theme.heading_min_height_after if sect.blocks? && @theme.heading_min_height_after
- start_new_page unless cursor > heading_height
- end
- # QUESTION: should we store pdf-page-start, pdf-anchor & pdf-destination in internal map?
- sect.set_attr 'pdf-page-start', (start_pgnum = page_number)
- # QUESTION: should we just assign the section this generated id?
- # NOTE: section must have pdf-anchor in order to be listed in the TOC
- sect.set_attr 'pdf-anchor', (sect_anchor = derive_anchor_from_id sect.id, %(#{start_pgnum}-#{y.ceil}))
- add_dest_for_block sect, id: sect_anchor, y: (at_page_top? ? page_height : nil)
+ hopts = { align: align, level: hlevel, outdent: !(part || chapterlike) }
+ if part
+ unless @theme.heading_part_break_before == 'auto'
+ start_new = true
+ theme_font(:heading, level: hlevel) { start_new_part sect }
+ end
+ elsif chapterlike
+ if @theme.heading_chapter_break_before != 'auto' ||
+ (@theme.heading_part_break_after == 'always' && sect == sect.parent.sections[0])
+ start_new = true
+ theme_font(:heading, level: hlevel) { start_new_chapter sect }
+ end
+ end
+ arrange_section sect, title, hopts unless start_new || at_page_top?
+ # QUESTION: should we store pdf-page-start, pdf-anchor & pdf-destination in internal map?
+ sect.set_attr 'pdf-page-start', (start_pgnum = page_number)
+ # QUESTION: should we just assign the section this generated id?
+ # NOTE: section must have pdf-anchor in order to be listed in the TOC
+ sect.set_attr 'pdf-anchor', (sect_anchor = derive_anchor_from_id sect.id, %(#{start_pgnum}-#{y.ceil}))
+ add_dest_for_block sect, id: sect_anchor, y: (at_page_top? ? page_height : nil)
+ theme_font :heading, level: hlevel do
if part
- layout_part_title sect, title, align: align, level: hlevel
+ layout_part_title sect, title, hopts
elsif chapterlike
- layout_chapter_title sect, title, align: align, level: hlevel unless sect.special && (sect.option? 'untitled')
+ layout_chapter_title sect, title, hopts unless sect.special && (sect.option? 'untitled')
else
- layout_general_heading sect, title, align: align, level: hlevel, outdent: true
+ layout_general_heading sect, title, hopts
end
end
@@ -2866,6 +2860,19 @@ module Asciidoctor
alias start_new_part start_new_chapter
+ def arrange_section sect, title, opts
+ theme_font :heading, level: (hlevel = opts[:level]) do
+ # FIXME: this height doesn't account for impact of text transform or inline formatting
+ heading_height =
+ (height_of_typeset_text title, line_height: (@theme[%(heading_h#{hlevel}_line_height)] || @theme.heading_line_height)) +
+ (@theme[%(heading_h#{hlevel}_margin_top)] || @theme.heading_margin_top) +
+ (@theme[%(heading_h#{hlevel}_margin_bottom)] || @theme.heading_margin_bottom)
+ heading_height += @theme.heading_min_height_after if sect.blocks? && @theme.heading_min_height_after
+ start_new_page unless cursor > heading_height
+ nil
+ end
+ end
+
def layout_chapter_title node, title, opts = {}
layout_general_heading node, title, (opts.merge outdent: true)
end
diff --git a/spec/section_spec.rb b/spec/section_spec.rb
index 4b1c5da5..9dfe6dd1 100644
--- a/spec/section_spec.rb
+++ b/spec/section_spec.rb
@@ -867,6 +867,46 @@ describe 'Asciidoctor::PDF::Converter - Section' do
(expect content_text[:page_number]).to be 2
end
+ it 'should allow arrange_section to be reimplemented to keep section with content that follows' do
+ backend = nil
+ create_class (Asciidoctor::Converter.for 'pdf') do
+ register_for (backend = %(pdf#{object_id}).to_sym)
+ def arrange_section sect, title, opts
+ orphaned = nil
+ dry_run single_page: true do
+ start_page = page
+ theme_font(:heading, level: opts[:level]) { layout_general_heading sect, title, opts }
+ next if page != start_page
+ page.tare_content_stream
+ orphaned = stop_if_first_page_empty { traverse sect }
+ end
+ start_new_page if orphaned
+ end
+ end
+
+ pdf = to_pdf <<~EOS, backend: backend, analyze: true
+ == Section A
+
+ image::tall.svg[pdfwidth=70mm]
+
+ == Section B
+
+ [%unbreakable]
+ --
+ keep
+
+ this
+
+ together
+ --
+ EOS
+
+ section_b_text = pdf.find_unique_text 'Section B'
+ (expect section_b_text[:page_number]).to be 2
+ content_text = pdf.find_unique_text 'keep'
+ (expect content_text[:page_number]).to be 2
+ end
+
it 'should not add break before chapter if heading-chapter-break-before key in theme is auto' do
pdf = to_pdf <<~'EOS', pdf_theme: { heading_chapter_break_before: 'auto' }, analyze: true
= Document Title