asciidoctor-pdf 2.1.1 → 2.1.4

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: bfcc8354e8152f540a4510dbddc39d38d577ee958aa51fbfb10b92d965abaa0c
4
- data.tar.gz: 68848a664ded97d88c45e2d8357f3880a5e10f4b6cc0f0c44b014cd85088d1ea
3
+ metadata.gz: eb8baebe850d75fcfc95460fbbdf89978867adb076acf572abaff0f51e18fb04
4
+ data.tar.gz: d4dbbaab4981db0666488ae108aee0f5851feb706e3846b13cd5cf46c341b5bc
5
5
  SHA512:
6
- metadata.gz: b1fb4074705e06fb70c188278e677c69f696e832d28d5ad49e6135b218ef36416abfaebfdedd980ff094579ae509d5006b59a52c57cf62374e9bdd69822b3714
7
- data.tar.gz: 07acff80d3d5c04e5ba8fbf591bbf3d952685bd0de605ac0e60645bbe478eafd1013451d4085abf8e2a41a996f5c4d8bba885377a1878a301ad75e144c0d2316
6
+ metadata.gz: 26b1c9830deeb0a39494e9cdb85fa5c2e2295efe8b3d527525b27c6dcf420a8ab94e06eeaca3431425e9cf547150d372bab49813af946cdd5ea0e155d6aad1f0
7
+ data.tar.gz: d584830d1eb1f76a005b48cf6a20030311d40184254d4ddfbd752f99a66c27feab85292c79012af0c9c4b7272a1727f402828f1c6d992228660ccbf78be44d2a
data/CHANGELOG.adoc CHANGED
@@ -5,6 +5,47 @@
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.1.4 (2022-06-26) - @mojavelinux
9
+
10
+ Improvements::
11
+
12
+ * include source location in warning message for truncated table cell if sourcemap is enabled (#2261)
13
+
14
+ Bug Fixes::
15
+
16
+ * allow alt text for block image, video, and audio to wrap to next line on same page (#2258)
17
+ * apply text-tranform from custom role on phrase after attributes have been resolved (#2263)
18
+ * make URL check more strict so image target containing a colon is not mistaken as a URL
19
+
20
+ === Details
21
+
22
+ {url-repo}/releases/tag/v2.1.4[git tag] | {url-repo}/compare/v2.1.3\...v2.1.4[full diff]
23
+
24
+ == 2.1.3 (2022-06-23) - @mojavelinux
25
+
26
+ Bug Fixes::
27
+
28
+ * interpret `start-at` theme keys with value `1` correctly (as `1` instead of `2`) (#2255)
29
+ * restore column layout after importing page(s) from PDF (#2253)
30
+ * fix crash when border color is transparent (`thematic-break-border-color`, `admonition-column-rule`, `quote-border-color`, `verse-border-color`)
31
+ * ensure page margin is restored after imported page
32
+
33
+ === Details
34
+
35
+ {url-repo}/releases/tag/v2.1.3[git tag] | {url-repo}/compare/v2.1.2\...v2.1.3[full diff]
36
+
37
+ == 2.1.2 (2022-06-17) - @mojavelinux
38
+
39
+ Bug Fixes::
40
+
41
+ * apply page layout from main document to new page in scratch document (#2248)
42
+ * use correct logic to insert page before TOC with automatic placement when doctype=book and media=prepress
43
+ * use `get_entries_for_toc` to determine if the TOC is non-empty rather than `Document#sections?`
44
+
45
+ === Details
46
+
47
+ {url-repo}/releases/tag/v2.1.2[git tag] | {url-repo}/compare/v2.1.1\...v2.1.2[full diff]
48
+
8
49
  == 2.1.1 (2022-06-15) - @mojavelinux
9
50
 
10
51
  Improvements::
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.1.1, 2022-06-15
3
+ v2.1.4, 2022-06-26
4
4
  // Settings:
5
5
  :experimental:
6
6
  :idprefix:
@@ -22,8 +22,6 @@ endif::[]
22
22
  // Aliases:
23
23
  :project-name: Asciidoctor PDF
24
24
  :project-handle: asciidoctor-pdf
25
- // Variables:
26
- :release-line: 2.1.x
27
25
  // URLs:
28
26
  :url-gem: https://rubygems.org/gems/asciidoctor-pdf
29
27
  :url-project: https://github.com/asciidoctor/asciidoctor-pdf
@@ -114,6 +114,7 @@ module Asciidoctor
114
114
  UriBreakCharsRx = %r((?:/|\?|&amp;|#)(?!$))
115
115
  UriBreakCharRepl = %(\\&#{ZeroWidthSpace})
116
116
  UriSchemeBoundaryRx = %r((?<=://))
117
+ UrlSniffRx = %r(^\p{Alpha}[\p{Alnum}+.-]*://)
117
118
  LineScanRx = /\n|.+/
118
119
  BlankLineRx = /\n{2,}/
119
120
  CjkLineBreakRx = /(?=[\u3000\u30a0-\u30ff\u3040-\u309f\p{Han}\uff00-\uffef])/
@@ -198,8 +199,8 @@ module Asciidoctor
198
199
 
199
200
  indent_section do
200
201
  toc_num_levels = (doc.attr 'toclevels', 2).to_i
201
- if (insert_toc = (doc.attr? 'toc') && !((toc_placement = doc.attr 'toc-placement') == 'macro' || toc_placement == 'preamble') && doc.sections?)
202
- start_toc_page doc, toc_placement if title_page_on
202
+ if (insert_toc = (doc.attr? 'toc') && !((toc_placement = doc.attr 'toc-placement') == 'macro' || toc_placement == 'preamble') && !(get_entries_for_toc doc).empty?)
203
+ start_new_page if @ppbook && verso_page?
203
204
  add_dest_for_block doc, id: 'toc', y: (at_page_top? ? page_height : nil)
204
205
  @toc_extent = allocate_toc doc, toc_num_levels, cursor, title_page_on
205
206
  else
@@ -213,7 +214,7 @@ module Asciidoctor
213
214
  first_page_offset = has_title_page ? zero_page_offset.next : zero_page_offset
214
215
  body_offset = (body_start_page_number = page_number) - 1
215
216
  if ::Integer === (running_content_start_at = @theme.running_content_start_at)
216
- running_content_body_offset = body_offset + [running_content_start_at.pred, 1].max
217
+ running_content_body_offset = body_offset + [running_content_start_at.pred, 0].max
217
218
  running_content_start_at = 'body'
218
219
  else
219
220
  running_content_body_offset = body_offset
@@ -227,7 +228,7 @@ module Asciidoctor
227
228
  end
228
229
  end
229
230
  if ::Integer === (page_numbering_start_at = @theme.page_numbering_start_at)
230
- page_numbering_body_offset = body_offset + [page_numbering_start_at.pred, 1].max
231
+ page_numbering_body_offset = body_offset + [page_numbering_start_at.pred, 0].max
231
232
  page_numbering_start_at = 'body'
232
233
  else
233
234
  page_numbering_body_offset = body_offset
@@ -263,12 +264,12 @@ module Asciidoctor
263
264
  else
264
265
  body_offset = body_start_page_number - 1
265
266
  if ::Integer === (running_content_start_at = @theme.running_content_start_at)
266
- running_content_body_offset = body_offset + [running_content_start_at.pred, 1].max
267
+ running_content_body_offset = body_offset + [running_content_start_at.pred, 0].max
267
268
  else
268
269
  running_content_body_offset = body_offset
269
270
  end
270
271
  if ::Integer === (page_numbering_start_at = @theme.page_numbering_start_at)
271
- page_numbering_body_offset = body_offset + [page_numbering_start_at.pred, 1].max
272
+ page_numbering_body_offset = body_offset + [page_numbering_start_at.pred, 0].max
272
273
  elsif page_numbering_start_at == 'cover' && has_front_cover
273
274
  page_numbering_body_offset = 0
274
275
  else
@@ -371,8 +372,6 @@ module Asciidoctor
371
372
  if (page_margin_inner = theme.page_margin_inner)
372
373
  page_margin_recto[3] = page_margin_verso[1] = page_margin_inner
373
374
  end
374
- # NOTE: prepare scratch document to use page margin from recto side (which has same width as verso side)
375
- set_page_margin page_margin_recto unless page_margin_recto == page_margin
376
375
  else
377
376
  @ppbook = nil
378
377
  end
@@ -581,6 +580,7 @@ module Asciidoctor
581
580
  end
582
581
 
583
582
  def prepare_theme theme
583
+ theme.base_border_color = nil if theme.base_border_color == 'transparent'
584
584
  theme.base_font_color ||= '000000'
585
585
  theme.base_font_size ||= 12
586
586
  theme.base_font_style = theme.base_font_style&.to_sym || :normal
@@ -943,7 +943,7 @@ module Asciidoctor
943
943
  if extent
944
944
  label_height = extent.single_page_height || cursor
945
945
  if (rule_width = @theme.admonition_column_rule_width || 0) > 0 &&
946
- (rule_color = @theme.admonition_column_rule_color || @theme.base_border_color)
946
+ (rule_color = resolve_theme_color :admonition_column_rule_color, @theme.base_border_color, nil)
947
947
  rule_style = @theme.admonition_column_rule_style&.to_sym || :solid
948
948
  float do
949
949
  extent.each_page do |first_page, last_page|
@@ -1273,7 +1273,7 @@ module Asciidoctor
1273
1273
  category = node.context == :quote ? :quote : :verse
1274
1274
  # NOTE: b_width and b_left_width are mutually exclusive
1275
1275
  if (b_left_width = @theme[%(#{category}_border_left_width)]) && b_left_width > 0
1276
- b_color = @theme[%(#{category}_border_color)] || @theme.base_border_color
1276
+ b_left_width = nil unless (b_color = resolve_theme_color %(#{category}_border_color), @theme.base_border_color, nil)
1277
1277
  else
1278
1278
  b_left_width = nil
1279
1279
  b_width = nil if (b_width = @theme[%(#{category}_border_width)]) == 0
@@ -1887,7 +1887,7 @@ module Asciidoctor
1887
1887
  add_dest_for_block node if node.id
1888
1888
  audio_path = node.media_uri node.attr 'target'
1889
1889
  play_symbol = (node.document.attr? 'icons', 'font') ? %(<font name="fas">#{(icon_font_data 'fas').unicode 'play'}</font>) : RightPointer
1890
- ink_prose %(#{play_symbol}#{NoBreakSpace}<a href="#{audio_path}">#{audio_path}</a> <em>(audio)</em>), normalize: false, margin: 0, single_line: true
1890
+ ink_prose %(#{play_symbol}#{NoBreakSpace}<a href="#{audio_path}">#{audio_path}</a> <em>(audio)</em>), normalize: false, margin: 0
1891
1891
  ink_caption node, labeled: false, end: :bottom if node.title?
1892
1892
  theme_margin :block, :bottom, (next_enclosed_block node)
1893
1893
  end
@@ -1915,7 +1915,7 @@ module Asciidoctor
1915
1915
  if poster.nil_or_empty?
1916
1916
  add_dest_for_block node if node.id
1917
1917
  play_symbol = (node.document.attr? 'icons', 'font') ? %(<font name="fas">#{(icon_font_data 'fas').unicode 'play'}</font>) : RightPointer
1918
- ink_prose %(#{play_symbol}#{NoBreakSpace}<a href="#{video_path}">#{video_path}</a> <em>(#{type})</em>), normalize: false, margin: 0, single_line: true
1918
+ ink_prose %(#{play_symbol}#{NoBreakSpace}<a href="#{video_path}">#{video_path}</a> <em>(#{type})</em>), normalize: false, margin: 0
1919
1919
  ink_caption node, labeled: false, end: :bottom if node.title?
1920
1920
  theme_margin :block, :bottom, (next_enclosed_block node)
1921
1921
  else
@@ -2054,7 +2054,8 @@ module Asciidoctor
2054
2054
  content: cell_text,
2055
2055
  colspan: cell.colspan || 1,
2056
2056
  align: (cell.attr 'halign').to_sym,
2057
- valign: (val = cell.attr 'valign') == 'middle' ? :center : val.to_sym
2057
+ valign: (val = cell.attr 'valign') == 'middle' ? :center : val.to_sym,
2058
+ source_location: cell.source_location
2058
2059
  end)
2059
2060
  end
2060
2061
  end unless head_rows.empty?
@@ -2073,7 +2074,8 @@ module Asciidoctor
2073
2074
  colspan: cell.colspan || 1,
2074
2075
  rowspan: cell.rowspan || 1,
2075
2076
  align: (cell.attr 'halign').to_sym,
2076
- valign: (val = cell.attr 'valign') == 'middle' ? :center : val.to_sym
2077
+ valign: (val = cell.attr 'valign') == 'middle' ? :center : val.to_sym,
2078
+ source_location: cell.source_location
2077
2079
  cell_line_metrics = body_cell_line_metrics
2078
2080
  case cell.style
2079
2081
  when :emphasis
@@ -2134,7 +2136,7 @@ module Asciidoctor
2134
2136
  # NOTE: line metrics get applied when AsciiDoc content is converted
2135
2137
  cell_line_metrics = nil
2136
2138
  asciidoc_cell = ::Prawn::Table::Cell::AsciiDoc.new self, (cell_data.merge content: cell.inner_document, padding: body_cell_padding)
2137
- cell_data = { content: asciidoc_cell }
2139
+ cell_data = { content: asciidoc_cell, source_location: cell.source_location }
2138
2140
  end
2139
2141
  if cell_line_metrics
2140
2142
  cell_padding = body_cell_padding.dup
@@ -2341,9 +2343,11 @@ module Asciidoctor
2341
2343
 
2342
2344
  def convert_thematic_break node
2343
2345
  pad_box @theme.thematic_break_padding || [@theme.thematic_break_margin_top, 0] do
2344
- stroke_horizontal_rule @theme.thematic_break_border_color,
2345
- line_width: @theme.thematic_break_border_width,
2346
- line_style: (@theme.thematic_break_border_style&.to_sym || :solid)
2346
+ if (b_color = resolve_theme_color :thematic_break_border_color)
2347
+ stroke_horizontal_rule b_color,
2348
+ line_width: @theme.thematic_break_border_width,
2349
+ line_style: (@theme.thematic_break_border_style&.to_sym || :solid)
2350
+ end
2347
2351
  end
2348
2352
  conceal_page_top { theme_margin :block, :bottom, (next_enclosed_block node) }
2349
2353
  end
@@ -2352,7 +2356,7 @@ module Asciidoctor
2352
2356
  # NOTE: only allow document to have a single managed toc
2353
2357
  return if @toc_extent
2354
2358
  is_macro = (placement = opts[:placement] || 'macro') == 'macro'
2355
- if ((doc = node.document).attr? 'toc-placement', placement) && (doc.attr? 'toc') && doc.sections?
2359
+ if ((doc = node.document).attr? 'toc-placement', placement) && (doc.attr? 'toc') && !(get_entries_for_toc doc).empty?
2356
2360
  start_toc_page node, placement if (is_book = doc.doctype == 'book')
2357
2361
  add_dest_for_block node, id: (node.id || 'toc') if is_macro
2358
2362
  toc_extent = @toc_extent = allocate_toc doc, (doc.attr 'toclevels', 2).to_i, cursor, (title_page_on = is_book || (doc.attr? 'title-page'))
@@ -2684,13 +2688,7 @@ module Asciidoctor
2684
2688
  end
2685
2689
 
2686
2690
  if (roles = node.role)
2687
- theme = load_theme node.document
2688
- roles.split.each do |role|
2689
- if (text_transform = theme[%(role_#{role}_text_transform)])
2690
- inner_text = transform_text inner_text, text_transform
2691
- end
2692
- inner_text = inner_text.gsub DoubleSpaceRx, ' ' + ZeroWidthSpace if role == 'pre-wrap' && (inner_text.include? DoubleSpace)
2693
- end
2691
+ inner_text = inner_text.gsub DoubleSpaceRx, ' ' + ZeroWidthSpace if (node.has_role? 'pre-wrap') && (inner_text.include? DoubleSpace)
2694
2692
  quoted_text = is_tag ? %(#{open.chop} class="#{roles}">#{inner_text}#{close}) : %(<span class="#{roles}">#{open}#{inner_text}#{close}</span>)
2695
2693
  else
2696
2694
  quoted_text = %(#{open}#{inner_text}#{close})
@@ -2802,13 +2800,7 @@ module Asciidoctor
2802
2800
  value = (value.split LF).delete_if {|line| SimpleAttributeRefRx.match? line }.join LF if opts[:drop_lines_with_unresolved_attributes] && (value.include? '{')
2803
2801
  value = value.gsub '\{', '{' if escaped_attr_ref
2804
2802
  doc.set_attr 'attribute-missing', attribute_missing unless attribute_missing == 'skip'
2805
- if imagesdir
2806
- if imagesdir_to_restore
2807
- doc.set_attr 'imagesdir', imagesdir_to_restore
2808
- else
2809
- doc.remove_attr 'imagesdir'
2810
- end
2811
- end
2803
+ imagesdir_to_restore ? (doc.set_attr 'imagesdir', imagesdir_to_restore) : (doc.remove_attr 'imagesdir') if imagesdir
2812
2804
  value
2813
2805
  end
2814
2806
 
@@ -3246,7 +3238,8 @@ module Asciidoctor
3246
3238
  end
3247
3239
  end
3248
3240
 
3249
- # NOTE: inline_format is true by default
3241
+ # NOTE: inline_format option is true by default
3242
+ # NOTE: single_line option is not compatible with this method
3250
3243
  def ink_prose string, opts = {}
3251
3244
  top_margin = (margin = (opts.delete :margin)) || (opts.delete :margin_top) || 0
3252
3245
  bot_margin = margin || (opts.delete :margin_bottom) || @theme.prose_margin_bottom
@@ -4260,10 +4253,10 @@ module Asciidoctor
4260
4253
  # NOTE: this will catch a classloader resource path on JRuby (e.g., uri:classloader:/path/to/image)
4261
4254
  elsif ::File.absolute_path? image_path
4262
4255
  ::File.absolute_path image_path
4263
- elsif !(is_uri = node.is_uri? image_path) && imagesdir && (::File.absolute_path? imagesdir)
4256
+ elsif !(is_url = url? image_path) && imagesdir && (::File.absolute_path? imagesdir)
4264
4257
  ::File.absolute_path image_path, imagesdir
4265
4258
  # handle case when image is a URI
4266
- elsif is_uri || (imagesdir && (node.is_uri? imagesdir) && (image_path = node.normalize_web_path image_path, imagesdir, false))
4259
+ elsif is_url || (imagesdir && (url? imagesdir) && (image_path = node.normalize_web_path image_path, imagesdir, false))
4267
4260
  if !allow_uri_read
4268
4261
  log :warn, %(cannot embed remote image: #{image_path} (allow-uri-read attribute not enabled))
4269
4262
  return
@@ -4501,6 +4494,7 @@ module Asciidoctor
4501
4494
  end
4502
4495
 
4503
4496
  # TODO: document me, esp the first line formatting functionality
4497
+ # NOTE: single_line option should only be used if height option is specified
4504
4498
  def typeset_text string, line_metrics, opts = {}
4505
4499
  opts = { leading: line_metrics.leading, final_gap: line_metrics.final_gap }.merge opts
4506
4500
  string = string.gsub CjkLineBreakRx, ZeroWidthSpace if @cjk_line_breaks
@@ -4823,18 +4817,17 @@ module Asciidoctor
4823
4817
  end
4824
4818
 
4825
4819
  # NOTE: init_page is called within a float context; this will suppress prawn-svg messing with the cursor
4826
- # NOTE: init_page is not called for imported pages, front and back cover pages, and other image pages
4820
+ # NOTE: init_page is not called for imported pages, cover pages, image pages, and pages in the scratch document
4827
4821
  def init_page *_args
4828
4822
  next_page_side = page_side nil, @folio_placement[:inverted]
4829
4823
  if @media == 'prepress' && (next_page_margin = @page_margin_by_side[page_number == 1 ? :cover : next_page_side]) != page_margin
4830
4824
  set_page_margin next_page_margin
4831
4825
  end
4832
4826
  unless @page_bg_color == 'FFFFFF'
4833
- tare = true
4834
4827
  fill_absolute_bounds @page_bg_color
4828
+ tare = true
4835
4829
  end
4836
4830
  if (bg_image_path, bg_image_opts = @page_bg_image[next_page_side])
4837
- tare = true
4838
4831
  begin
4839
4832
  if bg_image_opts[:format] == 'pdf'
4840
4833
  # NOTE: pages that use PDF for the background do not support a background color or running content
@@ -4843,6 +4836,7 @@ module Asciidoctor
4843
4836
  else
4844
4837
  canvas { image bg_image_path, ({ position: :center, vposition: :center }.merge bg_image_opts) }
4845
4838
  end
4839
+ tare = true
4846
4840
  rescue
4847
4841
  facing_page_side = (PageSides - [next_page_side])[0]
4848
4842
  @page_bg_image[facing_page_side] = nil if @page_bg_image[facing_page_side] == @page_bg_image[next_page_side]
@@ -4955,7 +4949,7 @@ module Asciidoctor
4955
4949
  alt_text_vars[:'/link'] = ''
4956
4950
  end
4957
4951
  theme_font :image_alt do
4958
- ink_prose alt_text_template % alt_text_vars, align: opts[:align], margin: 0, normalize: false, single_line: true
4952
+ ink_prose alt_text_template % alt_text_vars, align: opts[:align], margin: 0, normalize: false
4959
4953
  end
4960
4954
  ink_caption node, category: :image, end: :bottom if node.title?
4961
4955
  theme_margin :block, :bottom, (next_enclosed_block node) unless opts[:pinned]
@@ -5037,10 +5031,8 @@ module Asciidoctor
5037
5031
  # QUESTION: should we pass a category as an argument?
5038
5032
  # QUESTION: should we make this a method on the theme ostruct? (e.g., @theme.resolve_color key, fallback)
5039
5033
  def resolve_theme_color key, fallback_color = nil, transparent_color = fallback_color
5040
- if (color = @theme[key])
5034
+ if (color = @theme[key] || fallback_color)
5041
5035
  color == 'transparent' ? transparent_color : color
5042
- else
5043
- fallback_color
5044
5036
  end
5045
5037
  end
5046
5038
 
@@ -5052,6 +5044,10 @@ module Asciidoctor
5052
5044
  false
5053
5045
  end
5054
5046
 
5047
+ def url? str
5048
+ (str.include? ':/') && (UrlSniffRx.match? str)
5049
+ end
5050
+
5055
5051
  # Calculate the width that is needed to print all the
5056
5052
  # fragments without wrapping any lines.
5057
5053
  #
@@ -5120,6 +5116,10 @@ module Asciidoctor
5120
5116
  end
5121
5117
 
5122
5118
  def init_scratch originator
5119
+ if @media == 'prepress' && page_margin != (page_margin_recto = @page_margin_by_side[:recto])
5120
+ # NOTE: prepare scratch document to use page margin from recto side (which has same width as verso side)
5121
+ set_page_margin page_margin_recto
5122
+ end
5123
5123
  @scratch_prototype = originator.instance_variable_get :@scratch_prototype
5124
5124
  @tmp_files = originator.instance_variable_get :@tmp_files
5125
5125
  text_formatter.scratch = true
@@ -6,20 +6,23 @@ Prawn::Document::ColumnBox.prepend (Module.new do
6
6
  def move_past_bottom
7
7
  (doc = @document).y = @y
8
8
  return if (@current_column = (@current_column + 1) % @columns) > 0
9
- par = @parent
10
- if (reset_y = @reflow_margins) && (reset_y == true || reset_y > doc.page_number)
11
- @y = par.absolute_top
12
- @height = par.height unless stretchy?
13
- end
9
+ parent_ = @parent
10
+ reset_top parent_ if (reflow_at = @reflow_margins) && (reflow_at == true || reflow_at > doc.page_number)
14
11
  initial_margins = doc.page.margins
15
- par.move_past_bottom
12
+ parent_.move_past_bottom
16
13
  if doc.page.margins != initial_margins
17
- doc.bounds = self.class.new doc, par, [(margin_box = doc.margin_box).absolute_left, @y],
14
+ doc.bounds = self.class.new doc, parent_, [(margin_box = doc.margin_box).absolute_left, @y],
18
15
  columns: @columns, reflow_margins: @reflow_margins, spacer: @spacer, width: margin_box.width, height: @height
19
16
  end
20
17
  nil
21
18
  end
22
19
 
20
+ def reset_top parent_ = @parent
21
+ @current_column = 0
22
+ @height = parent_.height unless stretchy?
23
+ @y = parent_.absolute_top
24
+ end
25
+
23
26
  # Rearranges the column box into a single column, where the original columns are in a single file. Used
24
27
  # for the purpose of computing the extent of content in a scratch document.
25
28
  def single_file
@@ -528,29 +528,6 @@ module Asciidoctor
528
528
  end
529
529
  end
530
530
 
531
- # Apply the text transform to the specified text.
532
- #
533
- # Supported transform values are "uppercase", "lowercase", or "none" (passed
534
- # as either a String or a Symbol). When the uppercase transform is applied to
535
- # the text, it correctly uppercases visible text while leaving markup and
536
- # named character entities unchanged. The none transform returns the text
537
- # unmodified.
538
- #
539
- def transform_text text, transform
540
- case transform
541
- when :uppercase, 'uppercase'
542
- uppercase_pcdata text
543
- when :lowercase, 'lowercase'
544
- lowercase_pcdata text
545
- when :capitalize, 'capitalize'
546
- capitalize_words_pcdata text
547
- when :smallcaps, 'smallcaps'
548
- smallcaps_pcdata text
549
- else
550
- text
551
- end
552
- end
553
-
554
531
  def hyphenate_text text, hyphenator
555
532
  hyphenate_words_pcdata text, hyphenator
556
533
  end
@@ -924,6 +901,8 @@ module Asciidoctor
924
901
  def import_page file, options = {}
925
902
  prev_page_layout = page.layout
926
903
  prev_page_size = page.size
904
+ prev_page_margin = page_margin
905
+ prev_bounds = bounds
927
906
  state.compress = false if state.compress # can't use compression if using template
928
907
  prev_text_rendering_mode = (defined? @text_rendering_mode) ? @text_rendering_mode : nil
929
908
  delete_current_page if options[:replace]
@@ -936,11 +915,15 @@ module Asciidoctor
936
915
  # NOTE: set page size & layout explicitly in case imported page differs
937
916
  # I'm not sure it's right to start a new page here, but unfortunately there's no other
938
917
  # way atm to prevent the size & layout of the imported page from affecting subsequent pages
939
- advance_page size: prev_page_size, layout: prev_page_layout if options.fetch :advance, true
918
+ if options.fetch :advance, true
919
+ advance_page layout: prev_page_layout, margin: prev_page_margin, size: prev_page_size
920
+ (@bounding_box = prev_bounds).reset_top if ColumnBox === prev_bounds
921
+ end
940
922
  elsif options.fetch :advance_if_missing, true
941
923
  delete_current_page
942
924
  # NOTE: see previous comment
943
- advance_page size: prev_page_size, layout: prev_page_layout
925
+ advance_page layout: prev_page_layout, margin: prev_page_margin, size: prev_page_size
926
+ @y = (@bounding_box = prev_bounds).reset_top if ColumnBox === prev_bounds
944
927
  else
945
928
  delete_current_page
946
929
  end
@@ -1112,7 +1095,8 @@ module Asciidoctor
1112
1095
  # This method performs all work in a scratch document (or documents). It begins by starting a
1113
1096
  # new page in the scratch document, first creating the scratch document if necessary. It then
1114
1097
  # applies all the settings from the main document to the scratch document that impact
1115
- # rendering. This includes the bounds, the cursor position, and the font settings.
1098
+ # rendering. This includes the bounds, the cursor position, and the font settings. This method
1099
+ # assumes that the content area remains constant when content flows from one page to the next.
1116
1100
  #
1117
1101
  # From this point, the number of attempts the method makes is determined by the value of the
1118
1102
  # keep_together keyword parameter. If the value is true (or the parent document is inhibiting
@@ -1149,7 +1133,7 @@ module Asciidoctor
1149
1133
  #
1150
1134
  # Returns an Extent or ScratchExtent object that describes the bounds of the content block.
1151
1135
  def dry_run keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block
1152
- (scratch_pdf = scratch).start_new_page
1136
+ (scratch_pdf = scratch).start_new_page layout: page.layout
1153
1137
  saved_bounds = scratch_pdf.bounds
1154
1138
  scratch_pdf.bounds = bounds.dup.tap do |bounds_copy|
1155
1139
  bounds_copy.instance_variable_set :@document, scratch_pdf
@@ -91,7 +91,9 @@ module Prawn
91
91
  # TODO: apply horizontal alignment; currently it is necessary to specify alignment on content blocks
92
92
  apply_font_properties { pdf.traverse content }
93
93
  if (extra_pages = pdf.page_number - start_page) > 0
94
- logger.error %(the table cell on page #{start_page} has been truncated; Asciidoctor PDF does not support table cell content that exceeds the height of a single page) unless extra_pages == 1 && pdf.page.empty?
94
+ unless extra_pages == 1 && pdf.page.empty?
95
+ logger.error message_with_context %(the table cell on page #{start_page} has been truncated; Asciidoctor PDF does not support table cell content that exceeds the height of a single page), source_location: @source_location
96
+ end
95
97
  extra_pages.times { pdf.delete_current_page }
96
98
  end
97
99
  nil
@@ -16,7 +16,9 @@ class Prawn::Table::Cell::Text
16
16
  height: spanned_content_height + FPTolerance,
17
17
  at: [0, @pdf.cursor]).render
18
18
  end
19
- logger.error %(the table cell on page #{@pdf.page_number} has been truncated; Asciidoctor PDF does not support table cell content that exceeds the height of a single page) unless remaining_text.empty? || @pdf.scratch?
19
+ unless remaining_text.empty? || @pdf.scratch?
20
+ logger.error message_with_context %(the table cell on page #{@pdf.page_number} has been truncated; Asciidoctor PDF does not support table cell content that exceeds the height of a single page), source_location: @source_location
21
+ end
20
22
  end
21
23
  end
22
24
 
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Prawn::Table::Cell.prepend (Module.new do
4
+ attr_writer :source_location
5
+
4
6
  def border_color= color
5
7
  color = [color, color] if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === color
6
8
  super
@@ -4,6 +4,8 @@ module Asciidoctor
4
4
  module PDF
5
5
  module FormattedText
6
6
  class Transform
7
+ include TextTransformer
8
+
7
9
  LF = ?\n
8
10
  ZeroWidthSpace = ?\u200b
9
11
  CharEntityTable = { amp: '&', apos: ?', gt: '>', lt: '<', nbsp: ?\u00a0, quot: '"' }
@@ -21,8 +23,8 @@ module Asciidoctor
21
23
  'font_size' => :size,
22
24
  'text_decoration_color' => :text_decoration_color,
23
25
  'text_decoration_width' => :text_decoration_width,
26
+ 'text_transform' => :text_transform,
24
27
  }
25
- #DummyText = ?\u0000
26
28
 
27
29
  def initialize options = {}
28
30
  @merge_adjacent_text_nodes = options[:merge_adjacent_text_nodes]
@@ -96,7 +98,7 @@ module Asciidoctor
96
98
  }.compact,
97
99
  }
98
100
  @theme_settings.tap do |accum|
99
- revise_roles = [].to_set
101
+ roles_with_styles = [].to_set
100
102
  theme.each_pair do |key, val|
101
103
  next unless (key = key.to_s).start_with? 'role_'
102
104
  role, key = (key.slice 5, key.length).split '_', 2
@@ -110,10 +112,10 @@ module Asciidoctor
110
112
  # (accum[role] ||= {})[:kerning] = resolved_val
111
113
  # end
112
114
  elsif key == 'font_style' || key == 'text_decoration'
113
- revise_roles << role
115
+ roles_with_styles << role
114
116
  end
115
117
  end
116
- revise_roles.each do |role|
118
+ roles_with_styles.each do |role|
117
119
  (accum[role] ||= {})[:styles] = to_styles theme[%(role_#{role}_font_style)], theme[%(role_#{role}_text_decoration)]
118
120
  end
119
121
  end
@@ -172,6 +174,11 @@ module Asciidoctor
172
174
  previous_fragment_is_text && ((previous_fragment_text = fragments[-1][:text]).end_with? ' ')
173
175
  fragments[-1][:text] = previous_fragment_text.chop
174
176
  end
177
+ if (text_transform = fragment.delete :text_transform)
178
+ text = (text_chunks = extract_text pcdata).join
179
+ text_io = StringIO.new transform_text text, text_transform
180
+ restore_text pcdata, text_chunks.each_with_object([]) {|chunk, accum| accum << (text_io.read chunk.length) }
181
+ end
175
182
  # NOTE: decorate child fragments with inherited properties from this element
176
183
  apply pcdata, fragments, fragment
177
184
  previous_fragment_is_text = false
@@ -251,6 +258,8 @@ module Asciidoctor
251
258
  fragments
252
259
  end
253
260
 
261
+ private
262
+
254
263
  def build_fragment fragment, tag_name, attrs
255
264
  styles = (fragment[:styles] ||= ::Set.new)
256
265
  case tag_name
@@ -324,7 +333,6 @@ module Asciidoctor
324
333
  # NOTE: spaces in style value are superfluous for our purpose; split drops record after trailing ;
325
334
  attrs[:style].tr(' ', '').split(';').each do |style|
326
335
  pname, pvalue = style.split ':', 2
327
- # TODO: text-transform
328
336
  case pname
329
337
  when 'color' # color needed to support syntax highlighters
330
338
  fragment[:color] = pvalue.length == 7 ? (pvalue.slice 1, 6) : (pvalue.slice 1, 3).each_char.map {|c| c * 2 }.join if (pvalue.start_with? '#') && (HexColorRx.match? pvalue)
@@ -409,6 +417,29 @@ module Asciidoctor
409
417
  end
410
418
  end
411
419
  end
420
+
421
+ def extract_text pcdata
422
+ pcdata.reduce [] do |accum, it|
423
+ case it[:type]
424
+ when :text
425
+ accum << it[:value]
426
+ when :element
427
+ accum += (extract_text it[:pcdata]) if it.key? :pcdata
428
+ end
429
+ accum
430
+ end
431
+ end
432
+
433
+ def restore_text pcdata, text_chunks
434
+ pcdata.each do |it|
435
+ case it[:type]
436
+ when :text
437
+ it[:value] = text_chunks.shift
438
+ when :element
439
+ restore_text it[:pcdata], text_chunks if it.key? :pcdata
440
+ end
441
+ end
442
+ end
412
443
  end
413
444
  end
414
445
  end
@@ -3,7 +3,7 @@
3
3
  module Asciidoctor
4
4
  module PDF
5
5
  class IndexCatalog
6
- include ::Asciidoctor::PDF::TextTransformer
6
+ include TextTransformer
7
7
 
8
8
  LeadingAlphaRx = /^\p{Alpha}/
9
9
 
@@ -64,6 +64,29 @@ module Asciidoctor
64
64
  string.tr LowerAlphaChars, SmallCapsChars
65
65
  end
66
66
  end
67
+
68
+ # Apply the text transform to the specified text.
69
+ #
70
+ # Supported transform values are "uppercase", "lowercase", or "none" (passed
71
+ # as either a String or a Symbol). When the uppercase transform is applied to
72
+ # the text, it correctly uppercases visible text while leaving markup and
73
+ # named character entities unchanged. The none transform returns the text
74
+ # unmodified.
75
+ #
76
+ def transform_text text, transform
77
+ case transform
78
+ when :uppercase, 'uppercase'
79
+ uppercase_pcdata text
80
+ when :lowercase, 'lowercase'
81
+ lowercase_pcdata text
82
+ when :capitalize, 'capitalize'
83
+ capitalize_words_pcdata text
84
+ when :smallcaps, 'smallcaps'
85
+ smallcaps_pcdata text
86
+ else
87
+ text
88
+ end
89
+ end
67
90
  end
68
91
  end
69
92
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.1.1'
5
+ VERSION = '2.1.4'
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.1.1
4
+ version: 2.1.4
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-06-15 00:00:00.000000000 Z
12
+ date: 2022-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor