asciidoctor-pdf 2.0.0.rc.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09fac4d8ebb3877676d74d2fa320ae0a1f06cf2920d5560e98fde953de11cc08'
4
- data.tar.gz: e91be3fb2d14f512d058d8d01a15cbd2ec9ad58eace2fce55712e17b53e105e7
3
+ metadata.gz: c06c3e7edce9f473ace6df96c041850636e6561860f21a12725410370527ac27
4
+ data.tar.gz: a6fd22809163ed0d4fa07b8f2a51e0e20227e69f03a9af884c5512ff79d39a06
5
5
  SHA512:
6
- metadata.gz: 9407d5a3cf6e615f0c5a8a8d178c9257b111c385d91a699c55a4dd52b3fbe7c93da964eb13621740274f5b345fc08d035c7b01a7b998bcb2345081478a0cdf0f
7
- data.tar.gz: 51ccb076ce61906d75910950a41f95c37d11575506315c9324e9016a833d85ce2fb6d867ad051f3934ec4e475f79354cf602f25261bf440b307061c9e7aada92
6
+ metadata.gz: 397e550c0519ac08cab6af6f2ea2d598419a79c928a420d54ca296124a6ee6175a4005904c38c4a45e6cbdd5f01b61d410b673ad4133a018aafc69737b4c4c44
7
+ data.tar.gz: 19d24ba2f84be03ebff16a738224b1025a52e7a0d77c8dc1c3ffcc44d4c2a825989425da4ad00a886b3456c427287cd4b00b3943bbe13e4b9a4fb48b4842bb62
data/CHANGELOG.adoc CHANGED
@@ -5,6 +5,40 @@
5
5
  This document provides a high-level view of the changes to the {project-name} by release.
6
6
  For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
7
7
 
8
+ == 2.0.2 (2022-05-22) - @mojavelinux
9
+
10
+ Bug Fixes::
11
+
12
+ * use specified column widths to avoid bugs in column width calculation when using colspans (#1368)
13
+ * advance table to next page if rowspan in first row does not fit in space remaining on current page (#403)
14
+
15
+ === Details
16
+
17
+ {url-repo}/releases/tag/v2.0.2[git tag] | {url-repo}/compare/v2.0.1\...v2.0.2[full diff]
18
+
19
+ == 2.0.1 (2022-05-21) - @mojavelinux
20
+
21
+ Bug Fixes::
22
+
23
+ * scale inline image to fit within available height of page, accounting for the top padding of the line height and the bottom gutter (#2193)
24
+ * short-circuit formatted text routine and log error if fragments in first line cannot fit on an empty page
25
+ * break and wrap long contiguous text in source block when linenums is enabled (#2198)
26
+
27
+ === Details
28
+
29
+ {url-repo}/releases/tag/v2.0.1[git tag] | {url-repo}/compare/v2.0.0\...v2.0.1[full diff]
30
+
31
+ == 2.0.0 (2022-05-18) - @mojavelinux
32
+
33
+ Improvements::
34
+
35
+ * use more stable approach to recreating current bounds in scratch document
36
+ * add foundation to support multi-column layout for the body of an article (using an extended converter only)
37
+
38
+ === Details
39
+
40
+ {url-repo}/releases/tag/v2.0.0[git tag] | {url-repo}/compare/v2.0.0.rc.1\...v2.0.0[full diff]
41
+
8
42
  == 2.0.0.rc.1 (2022-05-17) - @mojavelinux
9
43
 
10
44
  Enhancements::
@@ -95,6 +129,7 @@ Enhancements::
95
129
  * use `base-border-color` as default border color; control appearance of border using `border-width` value alone (#2134)
96
130
  * remove border colors in base theme so all border colors can be controlled using `base-border-color` when extending theme
97
131
  * enable running footer when using base theme
132
+ * allow built-in optimizer to set PDF compliance flag (PDF/A and PDF/X) using value of `optimize` attribute (#125)
98
133
 
99
134
  Bug Fixes::
100
135
 
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor PDF: A native PDF converter for AsciiDoc
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.0.rc.1, 2022-05-17
3
+ v2.0.2, 2022-05-22
4
4
  // Settings:
5
5
  :experimental:
6
6
  :idprefix:
@@ -24,7 +24,7 @@ endif::[]
24
24
  :project-handle: asciidoctor-pdf
25
25
  // Variables:
26
26
  :release-line: 2.0.x
27
- :release-version: 2.0.0.rc.1
27
+ :release-version: 2.0.2
28
28
  // URLs:
29
29
  :url-gem: https://rubygems.org/gems/asciidoctor-pdf
30
30
  :url-project: https://github.com/asciidoctor/asciidoctor-pdf
@@ -152,7 +152,7 @@ module Asciidoctor
152
152
  # TODO: delegate to convert_method_missing
153
153
  log :warn, %(missing convert handler for #{name} node in #{@backend} backend)
154
154
  end
155
- # NOTE: inline nodes generate pseudo-HTML strings; the remainder write directly to PDF object
155
+ # NOTE: inline node handlers generate HTML-like strings; all other handlers write directly to the PDF object
156
156
  ::Asciidoctor::Inline === node ? result : self
157
157
  end
158
158
 
@@ -717,7 +717,7 @@ module Asciidoctor
717
717
  when 'page'
718
718
  pagenums = term.dests.uniq {|dest| dest[:page] }.map {|dest| %(<a anchor="#{dest[:anchor]}">#{dest[:page]}</a>) }
719
719
  when 'range'
720
- first_anchor_per_page = term.dests.each_with_object({}) {|dest, accum| accum[dest[:page]] ||= dest[:anchor] }
720
+ first_anchor_per_page = {}.tap {|accum| term.dests.each {|dest| accum[dest[:page]] ||= dest[:anchor] } }
721
721
  pagenums = (consolidate_ranges first_anchor_per_page.keys).map do |range|
722
722
  anchor = first_anchor_per_page[(range.include? '-') ? (range.partition '-')[0] : range]
723
723
  %(<a anchor="#{anchor}">#{range}</a>)
@@ -814,7 +814,7 @@ module Asciidoctor
814
814
  if (text_align = resolve_text_align_from_role (roles = node.roles), query_theme: true, remove_predefined: true)
815
815
  prose_opts[:align] = text_align
816
816
  end
817
- role_keys = roles.map {|role| %(role_#{role}).to_sym } unless roles.empty?
817
+ role_keys = roles.map {|role| %(role_#{role}) } unless roles.empty?
818
818
  if (text_indent = @theme.prose_text_indent) > 0 ||
819
819
  ((text_indent = @theme.prose_text_indent_inner) > 0 && node.previous_sibling&.context == :paragraph)
820
820
  prose_opts[:indent_paragraphs] = text_indent
@@ -1081,7 +1081,7 @@ module Asciidoctor
1081
1081
  highlight_lines = nil
1082
1082
  else
1083
1083
  pg_highlight_bg_color = pg_block_styles[:highlight_background_color]
1084
- highlight_lines = highlight_lines.map {|linenum| [linenum, pg_highlight_bg_color] }.to_h
1084
+ highlight_lines = {}.tap {|accum| highlight_lines.each {|linenum| accum[linenum] = pg_highlight_bg_color } }
1085
1085
  end
1086
1086
  end
1087
1087
  if (node.option? 'linenums') || (node.attr? 'linenums')
@@ -1120,7 +1120,7 @@ module Asciidoctor
1120
1120
  lexer ||= ::Rouge::Lexers::PlainText
1121
1121
  source_string, conum_mapping = extract_conums source_string if callouts_enabled
1122
1122
  if (node.attr? 'highlight') && !(hl_lines = (node.resolve_lines_to_highlight source_string, (node.attr 'highlight'))).empty?
1123
- formatter_opts[:highlight_lines] = hl_lines.map {|linenum| [linenum, true] }.to_h
1123
+ formatter_opts[:highlight_lines] = {}.tap {|accum| hl_lines.each {|linenum| accum[linenum] = true } }
1124
1124
  end
1125
1125
  fragments = formatter.format (lexer.lex source_string), formatter_opts rescue [text: source_string]
1126
1126
  source_chunks = conum_mapping ? (restore_conums fragments, conum_mapping) : fragments
@@ -1396,7 +1396,7 @@ module Asciidoctor
1396
1396
  end
1397
1397
  theme_margin :prose, :bottom, (next_enclosed_block actual_node) #unless actual_node.nested?
1398
1398
  when 'qanda'
1399
- @list_numerals << '1'
1399
+ @list_numerals << 1
1400
1400
  convert_list node
1401
1401
  @list_numerals.pop
1402
1402
  else
@@ -2167,6 +2167,7 @@ module Asciidoctor
2167
2167
 
2168
2168
  left_padding = right_padding = nil
2169
2169
  table table_data, table_settings do
2170
+ @column_widths = column_widths unless column_widths.empty?
2170
2171
  # NOTE: call width to capture resolved table width
2171
2172
  table_width = width
2172
2173
  @pdf.ink_table_caption node, alignment, table_width, caption_max_width if node.title? && caption_end == :top
@@ -3261,64 +3262,70 @@ module Asciidoctor
3261
3262
  end
3262
3263
  end
3263
3264
 
3264
- colspec_dict = PageSides.each_with_object({}) do |side, acc|
3265
- side_trim_content_width = trim_content_width[side]
3266
- if (custom_colspecs = @theme[%(#{periphery}_#{side}_columns)] || @theme[%(#{periphery}_columns)])
3267
- case (colspecs = (custom_colspecs.to_s.tr ',', ' ').split).size
3268
- when 0, 1
3269
- colspecs = { left: '0', center: colspecs[0] || '100', right: '0' }
3270
- when 2
3271
- colspecs = { left: colspecs[0], center: '0', right: colspecs[1] }
3272
- else # 3
3273
- colspecs = { left: colspecs[0], center: colspecs[1], right: colspecs[2] }
3274
- end
3275
- tot_width = 0
3276
- side_colspecs = colspecs.map do |col, spec|
3277
- if (alignment_char = spec.chr).to_i.to_s == alignment_char
3278
- alignment = :left
3279
- rel_width = spec.to_f
3280
- else
3281
- alignment = AlignmentTable[alignment_char]
3282
- rel_width = (spec.slice 1, spec.length).to_f
3265
+ colspec_dict = {}.tap do |acc|
3266
+ PageSides.each do |side|
3267
+ side_trim_content_width = trim_content_width[side]
3268
+ if (custom_colspecs = @theme[%(#{periphery}_#{side}_columns)] || @theme[%(#{periphery}_columns)])
3269
+ case (colspecs = (custom_colspecs.to_s.tr ',', ' ').split).size
3270
+ when 0, 1
3271
+ colspecs = { left: '0', center: colspecs[0] || '100', right: '0' }
3272
+ when 2
3273
+ colspecs = { left: colspecs[0], center: '0', right: colspecs[1] }
3274
+ else # 3
3275
+ colspecs = { left: colspecs[0], center: colspecs[1], right: colspecs[2] }
3283
3276
  end
3284
- tot_width += rel_width
3285
- [col, align: alignment, width: rel_width, x: 0]
3286
- end.to_h
3287
- # QUESTION: should we allow the columns to overlap (capping width at 100%)?
3288
- side_colspecs.each {|_, colspec| colspec[:width] = (colspec[:width] / tot_width) * side_trim_content_width }
3289
- side_colspecs[:right][:x] = (side_colspecs[:center][:x] = side_colspecs[:left][:width]) + side_colspecs[:center][:width]
3290
- acc[side] = side_colspecs
3291
- else
3292
- acc[side] = {
3293
- left: { align: :left, width: side_trim_content_width, x: 0 },
3294
- center: { align: :center, width: side_trim_content_width, x: 0 },
3295
- right: { align: :right, width: side_trim_content_width, x: 0 },
3296
- }
3277
+ tot_width = 0
3278
+ side_colspecs = {}.tap do |accum|
3279
+ colspecs.each do |col, spec|
3280
+ if (alignment_char = spec.chr).to_i.to_s == alignment_char
3281
+ alignment = :left
3282
+ rel_width = spec.to_f
3283
+ else
3284
+ alignment = AlignmentTable[alignment_char]
3285
+ rel_width = (spec.slice 1, spec.length).to_f
3286
+ end
3287
+ tot_width += rel_width
3288
+ accum[col] = { align: alignment, width: rel_width, x: 0 }
3289
+ end
3290
+ end
3291
+ # QUESTION: should we allow the columns to overlap (capping width at 100%)?
3292
+ side_colspecs.each {|_, colspec| colspec[:width] = (colspec[:width] / tot_width) * side_trim_content_width }
3293
+ side_colspecs[:right][:x] = (side_colspecs[:center][:x] = side_colspecs[:left][:width]) + side_colspecs[:center][:width]
3294
+ acc[side] = side_colspecs
3295
+ else
3296
+ acc[side] = {
3297
+ left: { align: :left, width: side_trim_content_width, x: 0 },
3298
+ center: { align: :center, width: side_trim_content_width, x: 0 },
3299
+ right: { align: :right, width: side_trim_content_width, x: 0 },
3300
+ }
3301
+ end
3297
3302
  end
3298
3303
  end
3299
3304
 
3300
- content_dict = PageSides.each_with_object({}) do |side, acc|
3301
- side_content = {}
3302
- ColumnPositions.each do |position|
3303
- next if (val = @theme[%(#{periphery}_#{side}_#{position}_content)]).nil_or_empty?
3304
- val = val.to_s unless ::String === val
3305
- if (val.include? ':') && val =~ ImageAttributeValueRx
3306
- attrlist = $2
3307
- image_attrs = (AttributeList.new attrlist).parse %w(alt width)
3308
- image_path, image_format = ::Asciidoctor::Image.target_and_format $1, image_attrs
3309
- if (image_path = resolve_image_path doc, image_path, image_format, @themesdir) && (::File.readable? image_path)
3310
- image_opts = resolve_image_options image_path, image_format, image_attrs, container_size: [colspec_dict[side][position][:width], trim_content_height[side]]
3311
- side_content[position] = [image_path, image_opts, image_attrs['link']]
3305
+ content_dict = {}.tap do |acc|
3306
+ PageSides.each do |side|
3307
+ side_content = {}
3308
+ ColumnPositions.each do |position|
3309
+ next if (val = @theme[%(#{periphery}_#{side}_#{position}_content)]).nil_or_empty?
3310
+ val = val.to_s unless ::String === val
3311
+ if (val.include? ':') && val =~ ImageAttributeValueRx
3312
+ attrlist = $2
3313
+ image_attrs = (AttributeList.new attrlist).parse %w(alt width)
3314
+ image_path, image_format = ::Asciidoctor::Image.target_and_format $1, image_attrs
3315
+ if (image_path = resolve_image_path doc, image_path, image_format, @themesdir) && (::File.readable? image_path)
3316
+ image_opts = resolve_image_options image_path, image_format, image_attrs, container_size: [colspec_dict[side][position][:width], trim_content_height[side]]
3317
+ side_content[position] = [image_path, image_opts, image_attrs['link']]
3318
+ else
3319
+ # NOTE: allows inline image handler to report invalid reference and replace with alt text
3320
+ side_content[position] = %(image:#{image_path}[#{attrlist}])
3321
+ end
3312
3322
  else
3313
- # NOTE: allows inline image handler to report invalid reference and replace with alt text
3314
- side_content[position] = %(image:#{image_path}[#{attrlist}])
3323
+ side_content[position] = val
3315
3324
  end
3316
- else
3317
- side_content[position] = val
3318
3325
  end
3319
- end
3320
3326
 
3321
- acc[side] = side_content
3327
+ acc[side] = side_content
3328
+ end
3322
3329
  end
3323
3330
 
3324
3331
  if (trim_bg_color = trim_styles[:bg_color]) || trim_bg_image || trim_border_width > 0
@@ -3866,18 +3873,17 @@ module Asciidoctor
3866
3873
 
3867
3874
  def register_fonts font_catalog, fonts_dir
3868
3875
  return unless font_catalog
3869
- dirs = (fonts_dir.split ValueSeparatorRx, -1).map do |dir|
3870
- dir == 'GEM_FONTS_DIR' || dir.empty? ? ThemeLoader::FontsDir : dir
3871
- end
3876
+ dirs = (fonts_dir.split ValueSeparatorRx, -1).map {|dir| dir == 'GEM_FONTS_DIR' || dir.empty? ? ThemeLoader::FontsDir : dir }
3872
3877
  font_catalog.each do |key, styles|
3873
- styles = styles.each_with_object({}) do |(style, path), accum|
3874
- found = dirs.any? do |dir|
3875
- resolved_font_path = font_path path, dir
3876
- accum[style.to_sym] = resolved_font_path if ::File.readable? resolved_font_path
3878
+ register_font key => ({}.tap do |accum|
3879
+ styles.each do |style, path|
3880
+ found = dirs.any? do |dir|
3881
+ resolved_font_path = font_path path, dir
3882
+ accum[style.to_sym] = resolved_font_path if ::File.readable? resolved_font_path
3883
+ end
3884
+ raise ::Errno::ENOENT, ((File.absolute_path? path) ? %(#{path} not found) : %(#{path} not found in #{fonts_dir.gsub ValueSeparatorRx, ' or '})) unless found
3877
3885
  end
3878
- raise ::Errno::ENOENT, ((File.absolute_path? path) ? %(#{path} not found) : %(#{path} not found in #{fonts_dir.gsub ValueSeparatorRx, ' or '})) unless found
3879
- end
3880
- register_font key => styles
3886
+ end)
3881
3887
  end
3882
3888
  end
3883
3889
 
@@ -4256,7 +4262,7 @@ module Asciidoctor
4256
4262
  b_shift, b_gap_color = (b_width ||= 0.5) * 0.5, @page_bg_color
4257
4263
  end
4258
4264
  ink_caption node_with_caption, category: category if node_with_caption
4259
- extent.from.page += 1 unless extent.from.page == page_number # sanity check
4265
+ extent.from.page += 1 unless extent.from.page == page_number || ColumnBox === bounds # sanity check
4260
4266
  float do
4261
4267
  extent.each_page do |first_page, last_page|
4262
4268
  advance_page unless first_page
@@ -4578,14 +4584,16 @@ module Asciidoctor
4578
4584
  def consolidate_ranges nums
4579
4585
  if nums.size > 1
4580
4586
  prev = nil
4581
- nums.each_with_object [] do |num, accum|
4587
+ accum = []
4588
+ nums.each do |num|
4582
4589
  if prev && (prev.to_i + 1) == num.to_i
4583
4590
  accum[-1][1] = num
4584
4591
  else
4585
4592
  accum << [num]
4586
4593
  end
4587
4594
  prev = num
4588
- end.map {|range| range.join '-' }
4595
+ end
4596
+ accum.map {|range| range.join '-' }
4589
4597
  else
4590
4598
  nums
4591
4599
  end
@@ -4930,14 +4938,16 @@ module Asciidoctor
4930
4938
  result = yield
4931
4939
  else
4932
4940
  email = nil
4933
- original_attrs = AuthorAttributeNames.each_with_object({}) do |(prop_name, attr_name), accum|
4934
- accum[attr_name] = doc.attr attr_name
4935
- if (val = author[prop_name])
4936
- doc.set_attr attr_name, val
4937
- # NOTE: email attribute could be a url
4938
- email = val if prop_name == :email
4939
- else
4940
- doc.remove_attr attr_name
4941
+ original_attrs = {}.tap do |accum|
4942
+ AuthorAttributeNames.each do |prop_name, attr_name|
4943
+ accum[attr_name] = doc.attr attr_name
4944
+ if (val = author[prop_name])
4945
+ doc.set_attr attr_name, val
4946
+ # NOTE: email attribute could be a url
4947
+ email = val if prop_name == :email
4948
+ else
4949
+ doc.remove_attr attr_name
4950
+ end
4941
4951
  end
4942
4952
  end
4943
4953
  doc.set_attr 'url', ((email.include? '@') ? %(mailto:#{email}) : email) if email
@@ -4,7 +4,7 @@ Prawn::Font::AFM.instance_variable_set :@hide_m17n_warning, true
4
4
 
5
5
  require 'prawn/icon'
6
6
 
7
- Prawn::Icon::Compatibility.send :prepend, (::Module.new { def warning *_args; end })
7
+ Prawn::Icon::Compatibility.prepend (::Module.new { def warning *_args; end })
8
8
 
9
9
  module Asciidoctor
10
10
  module Prawn
@@ -13,6 +13,8 @@ module Asciidoctor
13
13
  include ::Asciidoctor::PDF::Sanitizer
14
14
  include ::Asciidoctor::PDF::TextTransformer
15
15
 
16
+ ColumnBox = ::Prawn::Document::ColumnBox
17
+
16
18
  FontAwesomeIconSets = %w(fab far fas)
17
19
  IconSets = %w(fab far fas fi pf).to_set
18
20
  IconSetPrefixes = IconSets.map {|it| it + '-' }
@@ -429,15 +431,19 @@ module Asciidoctor
429
431
 
430
432
  # NOTE: override built-in fill_formatted_text_box to insert leading before second line when :first_line is true
431
433
  def fill_formatted_text_box text, options
432
- if (initial_gap = options[:initial_gap]) && (first_text = text[0]) && first_text[:from_page] != page_number
434
+ if (initial_gap = options[:initial_gap]) && !text.empty? && text[0][:from_page] != page_number
433
435
  self.y -= initial_gap
434
436
  end
435
437
  merge_text_box_positioning_options options
436
438
  box = ::Prawn::Text::Formatted::Box.new text, options
437
- remaining_text = box.render
439
+ remaining_fragments = box.render
438
440
  @no_text_printed = box.nothing_printed?
439
441
  @all_text_printed = box.everything_printed?
440
- remaining_text[0][:from_page] = page_number unless remaining_text.empty?
442
+ unless remaining_fragments.empty? || (remaining_fragments[0][:from_page] ||= page_number) == page_number
443
+ log :error, %(cannot fit formatted text on page: #{remaining_fragments.map {|it| it[:image_path] || it[:text] }.join})
444
+ page.tare_content_stream
445
+ remaining_fragments = {}
446
+ end
441
447
 
442
448
  if @final_gap || (options[:first_line] && !(@no_text_printed || @all_text_printed))
443
449
  self.y -= box.height + box.line_gap + box.leading
@@ -445,7 +451,7 @@ module Asciidoctor
445
451
  self.y -= box.height
446
452
  end
447
453
 
448
- remaining_text
454
+ remaining_fragments
449
455
  end
450
456
 
451
457
  # NOTE: override built-in draw_indented_formatted_line to set first_line flag
@@ -481,7 +487,13 @@ module Asciidoctor
481
487
  else
482
488
  remaining_fragments = box.render dry_run: true
483
489
  end
484
- remaining_fragments.empty? ? (remaining_fragments = nil) : (remaining_fragments[0][:from_page] = page_number)
490
+ if remaining_fragments.empty?
491
+ remaining_fragments = nil
492
+ elsif (remaining_fragments[0][:from_page] ||= page_number) != page_number
493
+ log :error, %(cannot fit formatted text on page: #{remaining_fragments.map {|it| it[:image_path] || it[:text] }.join})
494
+ page.tare_content_stream
495
+ remaining_fragments = nil
496
+ end
485
497
  if first_line_text_transform
486
498
  # NOTE: applying text transform here could alter the wrapping, so isolate first line and shrink it to fit
487
499
  first_line_text = (box.instance_variable_get :@printed_lines)[0]
@@ -543,6 +555,18 @@ module Asciidoctor
543
555
 
544
556
  # Cursor
545
557
 
558
+ # Override the built-in float method to add support for restoring the current column of a ColumnBox
559
+ #
560
+ def float
561
+ original_page_number = page_number
562
+ original_y = y
563
+ original_column = bounds.instance_variable_get :@current_column if ColumnBox === bounds
564
+ yield
565
+ go_to_page original_page_number unless page_number == original_page_number
566
+ self.y = original_y
567
+ bounds.instance_variable_set :@current_column, original_column if original_column
568
+ end
569
+
546
570
  # Short-circuits the call to the built-in move_up operation
547
571
  # when n is 0.
548
572
  #
@@ -1118,10 +1142,14 @@ module Asciidoctor
1118
1142
  # Returns an Extent or ScratchExtent object that describes the bounds of the content block.
1119
1143
  def dry_run keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block
1120
1144
  (scratch_pdf = scratch).start_new_page
1121
- scratch_bounds = scratch_pdf.bounds
1122
- restore_bounds = [:@total_left_padding, :@total_right_padding, :@width, :@x].each_with_object({}) do |name, accum|
1123
- accum[name] = scratch_bounds.instance_variable_get name
1124
- scratch_bounds.instance_variable_set name, (bounds.instance_variable_get name)
1145
+ saved_bounds = scratch_pdf.bounds
1146
+ scratch_pdf.bounds = bounds.dup.tap do |bounds_copy|
1147
+ bounds_copy.instance_variable_set :@document, scratch_pdf
1148
+ bounds_copy.instance_variable_set :@parent, saved_bounds
1149
+ if ColumnBox === bounds_copy
1150
+ bounds_copy.instance_variable_set :@width, bounds_copy.bare_column_width
1151
+ bounds_copy.instance_variable_set :@current_column, (bounds_copy.instance_variable_set :@columns, 1) - 1
1152
+ end
1125
1153
  end
1126
1154
  scratch_pdf.move_cursor_to cursor unless (scratch_start_at_top = keep_together || pages_advanced > 0 || at_page_top?)
1127
1155
  scratch_start_cursor = scratch_pdf.cursor
@@ -1163,7 +1191,7 @@ module Asciidoctor
1163
1191
  extent = ScratchExtent.new scratch_start_page, scratch_start_cursor, scratch_end_page, scratch_end_cursor
1164
1192
  onto ? extent.position_onto(*onto) : extent
1165
1193
  ensure
1166
- restore_bounds.each {|name, val| scratch_bounds.instance_variable_set name, val }
1194
+ scratch_pdf.bounds = saved_bounds
1167
1195
  end
1168
1196
  end
1169
1197
  end
@@ -2,12 +2,15 @@
2
2
 
3
3
  module Prawn::Text::Formatted::ProtectBottomGutter
4
4
  def enough_height_for_this_line?
5
- return super unless @arranger.finished?
6
- begin
7
- @height -= @bottom_gutter
5
+ if @arranger.finished? && @arranger.fragments.none? {|it| it.format_state[:full_height] }
6
+ begin
7
+ @height -= @bottom_gutter
8
+ super
9
+ ensure
10
+ @height += @bottom_gutter
11
+ end
12
+ else
8
13
  super
9
- ensure
10
- @height += @bottom_gutter
11
14
  end
12
15
  end
13
16
  end
@@ -1,6 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'prawn/table'
4
+
5
+ Prawn::Table.prepend (Module.new do
6
+ def initial_row_on_initial_page
7
+ return 0 if fits_on_page? @pdf.bounds.height
8
+ height_required = (row (0..number_of_header_rows)).height_with_span
9
+ return -1 if fits_on_page? height_required, true
10
+ @pdf.bounds.move_past_bottom
11
+ 0
12
+ end
13
+ end)
14
+
4
15
  require_relative 'prawn-table/cell'
5
16
  require_relative 'prawn-table/cell/asciidoc'
6
17
  require_relative 'prawn-table/cell/text'
@@ -38,7 +38,7 @@ module Asciidoctor::PDF::FormattedText
38
38
  return if (raw_image_fragments = fragments.select {|f| (f.key? :image_path) && !(f.key? :image_obj) }).empty?
39
39
  scratch = doc.scratch?
40
40
  available_w = available_width
41
- available_h = doc.page.empty? ? doc.cursor : doc.bounds.height
41
+ available_h = doc.bounds.height
42
42
  last_fragment = {}
43
43
  raw_image_fragments.each do |fragment|
44
44
  if fragment[:object_id] == last_fragment[:object_id]
@@ -96,6 +96,10 @@ module Asciidoctor::PDF::FormattedText
96
96
  if (f_height = image_h) > (line_font = doc.font).height * 1.5
97
97
  # align with descender (equivalent to vertical-align: bottom in CSS)
98
98
  fragment[:ascender] = f_height - (fragment[:descender] = line_font.descender)
99
+ if f_height == available_h
100
+ fragment[:ascender] -= (doc.calc_line_metrics (doc.instance_variable_get :@base_line_height), line_font, doc.font_size).padding_top
101
+ fragment[:full_height] = true
102
+ end
99
103
  doc.font_size (fragment[:size] = f_height * (doc.font_size / line_font.height))
100
104
  # align with baseline (roughly equivalent to vertical-align: baseline in CSS)
101
105
  #fragment[:ascender] = f_height
@@ -11,15 +11,15 @@ module Asciidoctor
11
11
  def wrap array
12
12
  return super unless array[0][:linenum] # sanity check
13
13
  initialize_wrap array
14
+ @line_wrap.extend SourceLineWrap
14
15
  highlight_line = stop = nil
15
16
  unconsumed = @arranger.unconsumed
16
17
  until stop
17
18
  if (first_fragment = unconsumed[0])[:linenum]
18
19
  linenum_text = first_fragment[:text]
19
- linenum_spacer ||= { text: (NoBreakSpace.encode linenum_text.encoding) + (' ' * (linenum_text.length - 1)) }
20
+ linenum_spacer ||= { text: (NoBreakSpace.encode linenum_text.encoding) + (' ' * (linenum_text.length - 1)), linenum: :spacer }
20
21
  highlight_line = (second_fragment = unconsumed[1])[:highlight] ? second_fragment.dup : nil
21
- else
22
- # NOTE: a wrapped line
22
+ else # wrapped line
23
23
  first_fragment[:text] = first_fragment[:text].lstrip
24
24
  @arranger.unconsumed.unshift highlight_line if highlight_line
25
25
  @arranger.unconsumed.unshift linenum_spacer.dup
@@ -43,6 +43,12 @@ module Asciidoctor
43
43
  @arranger.unconsumed
44
44
  end
45
45
  end
46
+
47
+ module SourceLineWrap
48
+ def update_line_status_based_on_last_output
49
+ @arranger.current_format_state[:linenum] ? nil : super
50
+ end
51
+ end
46
52
  end
47
53
  end
48
54
  end
@@ -95,22 +95,24 @@ module Asciidoctor
95
95
  styles: (to_styles theme.menu_font_style),
96
96
  }.compact,
97
97
  }
98
- revise_roles = [].to_set
99
- theme.each_pair.each_with_object @theme_settings do |(key, val), accum|
100
- next unless (key = key.to_s).start_with? 'role_'
101
- role, key = (key.slice 5, key.length).split '_', 2
102
- if (prop = ThemeKeyToFragmentProperty[key])
103
- (accum[role] ||= {})[prop] = val
104
- #elsif key == 'font_kerning'
105
- # unless (resolved_val = val == 'none' ? false : (val == 'normal' ? true : nil)).nil?
106
- # (accum[role] ||= {})[:kerning] = resolved_val
107
- # end
108
- elsif key == 'font_style' || key == 'text_decoration'
109
- revise_roles << role
98
+ @theme_settings.tap do |accum|
99
+ revise_roles = [].to_set
100
+ theme.each_pair do |key, val|
101
+ next unless (key = key.to_s).start_with? 'role_'
102
+ role, key = (key.slice 5, key.length).split '_', 2
103
+ if (prop = ThemeKeyToFragmentProperty[key])
104
+ (accum[role] ||= {})[prop] = val
105
+ #elsif key == 'font_kerning'
106
+ # unless (resolved_val = val == 'none' ? false : (val == 'normal' ? true : nil)).nil?
107
+ # (accum[role] ||= {})[:kerning] = resolved_val
108
+ # end
109
+ elsif key == 'font_style' || key == 'text_decoration'
110
+ revise_roles << role
111
+ end
112
+ end
113
+ revise_roles.each do |role|
114
+ (accum[role] ||= {})[:styles] = to_styles theme[%(role_#{role}_font_style)], theme[%(role_#{role}_text_decoration)]
110
115
  end
111
- end
112
- revise_roles.each_with_object @theme_settings do |role, accum|
113
- (accum[role] ||= {})[:styles] = to_styles theme[%(role_#{role}_font_style)], theme[%(role_#{role}_text_decoration)]
114
116
  end
115
117
  @theme_settings['line-through'] = { styles: [:strikethrough].to_set } unless @theme_settings.key? 'line-through'
116
118
  @theme_settings['underline'] = { styles: [:underline].to_set } unless @theme_settings.key? 'underline'
@@ -276,8 +278,10 @@ module Asciidoctor
276
278
  when '#' # hex string (e.g., #FF0000)
277
279
  fragment[:color] = value.length == 7 ? (value.slice 1, 6) : (value.slice 1, 3).each_char.map {|c| c * 2 }.join if HexColorRx.match? value
278
280
  when '[' # CMYK array (e.g., [50, 100, 0, 0])
279
- fragment[:color] = ((((value.slice 1, value.length).chomp ']').split ', ', 4).each_with_object ::Array.new 4, 0).with_index do |(it, accum), idx|
280
- accum[idx] = (ival = it.to_i) == (fval = it.to_f) ? ival : fval
281
+ fragment[:color] = [0, 0, 0, 0].tap do |accum|
282
+ (((value.slice 1, value.length).chomp ']').split ', ', 4).each_with_index do |it, idx|
283
+ accum[idx] = (ival = it.to_i) == (fval = it.to_f) ? ival : fval
284
+ end
281
285
  end
282
286
  else # assume a 6-character hex color (internal only)
283
287
  fragment[:color] = value
@@ -15,9 +15,7 @@ module Asciidoctor
15
15
  BaseThemePath = ::File.join ThemesDir, 'base-theme.yml'
16
16
  BundledThemeNames = (::Dir.children ThemesDir).map {|it| it.slice 0, it.length - 10 }
17
17
  DeprecatedCategoryKeys = { 'blockquote' => 'quote', 'key' => 'kbd', 'literal' => 'codespan', 'outline_list' => 'list' }
18
- DeprecatedKeys = %w(base heading heading_h1 heading_h2 heading_h3 heading_h4 heading_h5 heading_h6 title_page abstract abstract_title admonition_label sidebar_title toc_title).each_with_object({ 'table_caption_side' => 'table_caption_end' }) do |prefix, accum|
19
- accum[%(#{prefix}_align)] = %(#{prefix}_text_align)
20
- end
18
+ DeprecatedKeys = { 'table_caption_side' => 'table_caption_end' }.tap {|accum| %w(base heading heading_h1 heading_h2 heading_h3 heading_h4 heading_h5 heading_h6 title_page abstract abstract_title admonition_label sidebar_title toc_title).each {|prefix| accum[%(#{prefix}_align)] = %(#{prefix}_text_align) } }
21
19
  PaddingBottomHackKeys = %w(example_padding quote_padding sidebar_padding verse_padding)
22
20
 
23
21
  VariableRx = /\$([a-z0-9_-]+)/
@@ -159,10 +157,12 @@ module Asciidoctor
159
157
  elsif key == 'font_fallbacks'
160
158
  data[key] = ::Array === val ? val.map {|name| expand_vars name.to_s, data } : []
161
159
  elsif key.start_with? 'admonition_icon_'
162
- data[key] = val.map do |(key2, val2)|
163
- key2 = key2.tr '-', '_' if key2.include? '-'
164
- [key2.to_sym, (key2.end_with? '_color') ? (to_color evaluate val2, data) : (evaluate val2, data)]
165
- end.to_h if val
160
+ data[key] = {}.tap do |accum|
161
+ val.each do |key2, val2|
162
+ key2 = key2.tr '-', '_' if key2.include? '-'
163
+ accum[key2.to_sym] = (key2.end_with? '_color') ? (to_color evaluate val2, data) : (evaluate val2, data)
164
+ end
165
+ end if val
166
166
  elsif ::Hash === val
167
167
  if (rekey = DeprecatedCategoryKeys[key])
168
168
  logger.warn %(the #{key.tr '_', '-'} theme category is deprecated; use the #{rekey.tr '_', '-'} category instead)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.0.0.rc.1'
5
+ VERSION = '2.0.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-05-17 00:00:00.000000000 Z
12
+ date: 2022-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor
@@ -325,9 +325,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
325
325
  version: '0'
326
326
  required_rubygems_version: !ruby/object:Gem::Requirement
327
327
  requirements:
328
- - - ">"
328
+ - - ">="
329
329
  - !ruby/object:Gem::Version
330
- version: 1.3.1
330
+ version: '0'
331
331
  requirements: []
332
332
  rubygems_version: 3.3.7
333
333
  signing_key: