asciidoctor-pdf 2.1.1 → 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +41 -0
- data/README.adoc +1 -3
- data/lib/asciidoctor/pdf/converter.rb +43 -43
- data/lib/asciidoctor/pdf/ext/prawn/document/column_box.rb +10 -7
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +11 -27
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +3 -1
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +3 -1
- data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +2 -0
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +36 -5
- data/lib/asciidoctor/pdf/index_catalog.rb +1 -1
- data/lib/asciidoctor/pdf/text_transformer.rb +23 -0
- data/lib/asciidoctor/pdf/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb8baebe850d75fcfc95460fbbdf89978867adb076acf572abaff0f51e18fb04
|
4
|
+
data.tar.gz: d4dbbaab4981db0666488ae108aee0f5851feb706e3846b13cd5cf46c341b5bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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((?:/|\?|&|#)(?!$))
|
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.
|
202
|
-
|
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,
|
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,
|
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,
|
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,
|
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 =
|
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 =
|
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
|
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
|
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
|
-
|
2345
|
-
|
2346
|
-
|
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.
|
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
|
-
|
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 !(
|
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
|
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,
|
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
|
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
|
-
|
10
|
-
if (
|
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
|
-
|
12
|
+
parent_.move_past_bottom
|
16
13
|
if doc.page.margins != initial_margins
|
17
|
-
doc.bounds = self.class.new doc,
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
|
@@ -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
|
-
|
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
|
-
|
115
|
+
roles_with_styles << role
|
114
116
|
end
|
115
117
|
end
|
116
|
-
|
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
|
@@ -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
|
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.
|
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-
|
12
|
+
date: 2022-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|