asciidoctor-pdf 2.0.0 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +39 -0
- data/README.adoc +3 -10
- data/lib/asciidoctor/pdf/converter.rb +115 -93
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +16 -6
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb +8 -5
- data/lib/asciidoctor/pdf/ext/prawn-table.rb +11 -0
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +5 -1
- data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +9 -3
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +21 -17
- data/lib/asciidoctor/pdf/theme_loader.rb +7 -7
- 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: b41dc215a6b942da9191850d15cf3e68224f1b633147b2df34a5e1e88756f797
|
4
|
+
data.tar.gz: 929dd071b2dc29b6d6f4500efb87e1ffa251c9413ae1e8076a14285bca51a600
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17d8c003b47e99e0e7156027783ff1fa1e8298767b82de209f40a523e40d6d1f35f7263c1b673bb686082a474a219c9fda26e3f2894852f51374dd554844aae2
|
7
|
+
data.tar.gz: 9711e5816aa9c9893ddaf139c717fb125d285b5788d42ebac4473660148f66126b1eccc1f389d781e4fc13ccb02010f9a909fa69580b7239765b907a160a4a3b
|
data/CHANGELOG.adoc
CHANGED
@@ -5,6 +5,45 @@
|
|
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.3 (2022-05-25) - @mojavelinux
|
9
|
+
|
10
|
+
Improvements::
|
11
|
+
|
12
|
+
* compute the optimize settings in init_pdf and store as Hash instead of after writing the PDF file
|
13
|
+
|
14
|
+
Bug Fixes::
|
15
|
+
|
16
|
+
* adjust TrimBox to fit inside of BleedBox when using optimizer and compliance is PDF/X (#2203)
|
17
|
+
* set height of resized image to available height to avoid float precision error when scaling down image to fit page (#2205)
|
18
|
+
* prevent content on title page from overrunning the bounds of a single page and warn; restriction applies to `ink_title_page`
|
19
|
+
|
20
|
+
=== Details
|
21
|
+
|
22
|
+
{url-repo}/releases/tag/v2.0.3[git tag] | {url-repo}/compare/v2.0.2\...v2.0.3[full diff]
|
23
|
+
|
24
|
+
== 2.0.2 (2022-05-22) - @mojavelinux
|
25
|
+
|
26
|
+
Bug Fixes::
|
27
|
+
|
28
|
+
* use specified column widths to avoid bugs in column width calculation when using colspans (#1368)
|
29
|
+
* advance table to next page if rowspan in first row does not fit in space remaining on current page (#403)
|
30
|
+
|
31
|
+
=== Details
|
32
|
+
|
33
|
+
{url-repo}/releases/tag/v2.0.2[git tag] | {url-repo}/compare/v2.0.1\...v2.0.2[full diff]
|
34
|
+
|
35
|
+
== 2.0.1 (2022-05-21) - @mojavelinux
|
36
|
+
|
37
|
+
Bug Fixes::
|
38
|
+
|
39
|
+
* scale inline image to fit within available height of page, accounting for the top padding of the line height and the bottom gutter (#2193)
|
40
|
+
* short-circuit formatted text routine and log error if fragments in first line cannot fit on an empty page
|
41
|
+
* break and wrap long contiguous text in source block when linenums is enabled (#2198)
|
42
|
+
|
43
|
+
=== Details
|
44
|
+
|
45
|
+
{url-repo}/releases/tag/v2.0.1[git tag] | {url-repo}/compare/v2.0.0\...v2.0.1[full diff]
|
46
|
+
|
8
47
|
== 2.0.0 (2022-05-18) - @mojavelinux
|
9
48
|
|
10
49
|
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.0.
|
3
|
+
v2.0.3, 2022-05-25
|
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.
|
27
|
+
:release-version: 2.0.3
|
28
28
|
// URLs:
|
29
29
|
:url-gem: https://rubygems.org/gems/asciidoctor-pdf
|
30
30
|
:url-project: https://github.com/asciidoctor/asciidoctor-pdf
|
@@ -97,14 +97,7 @@ Pass the name of the gem to the `gem install` command as follows:
|
|
97
97
|
Installing Asciidoctor PDF will install a number of other gems mentioned in these docs, including asciidoctor, prawn, prawn-svg, prawn-table, prawn-icon, and ttfunk.
|
98
98
|
For the most part, the versions of these dependencies are locked to the version of Asciidoctor PDF.
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
$ gem install matrix
|
103
|
-
|
104
|
-
The matrix gem used to be bundled in the Ruby distribution, but was split out starting in Ruby 3.1.
|
105
|
-
This requirement will be lifted once Prawn declares it as a runtime dependency.
|
106
|
-
|
107
|
-
For further installation information, see {url-project-docs}/install/[the installation documentation].
|
100
|
+
For further installation information about installing Asciidoctor PDF, see {url-project-docs}/install/[the installation documentation].
|
108
101
|
For troubleshooting help, see {url-project-docs}/install/#installation-troubleshooting[Installation troubleshooting].
|
109
102
|
|
110
103
|
=== Install a prerelease or development version
|
@@ -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
|
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
|
|
@@ -174,7 +174,9 @@ module Asciidoctor
|
|
174
174
|
if (has_title_page = (title_page_on = doc.doctype == 'book' || (doc.attr? 'title-page')) && (start_title_page doc))
|
175
175
|
# NOTE: the base font must be set before any content is written to the main or scratch document
|
176
176
|
font @theme.base_font_family, size: @root_font_size, style: @theme.base_font_style
|
177
|
-
ink_title_page doc
|
177
|
+
if perform_on_single_page { ink_title_page doc }
|
178
|
+
log :warn, 'the title page contents has been truncated to prevent it from overrunning the bounds of a single page'
|
179
|
+
end
|
178
180
|
start_new_page
|
179
181
|
else
|
180
182
|
@page_margin_by_side[:cover] = @page_margin_by_side[:recto] if @media == 'prepress' && page_number == 0
|
@@ -321,6 +323,7 @@ module Asciidoctor
|
|
321
323
|
stamp_foreground_image doc, has_front_cover
|
322
324
|
ink_cover_page doc, :back
|
323
325
|
add_dest_for_top doc
|
326
|
+
state.pages.each {|it| fit_trim_box it } if (@optimize&.[] :compliance)&.start_with? 'PDF/X'
|
324
327
|
nil
|
325
328
|
end
|
326
329
|
|
@@ -411,8 +414,14 @@ module Asciidoctor
|
|
411
414
|
# NOTE: we have to init Pdfmark class here while we have reference to the doc
|
412
415
|
@pdfmark = (doc.attr? 'pdfmark') ? (Pdfmark.new doc) : nil
|
413
416
|
# NOTE: defer instantiating optimizer until we know min pdf version
|
414
|
-
if (
|
415
|
-
|
417
|
+
if (optimize = doc.attr 'optimize') &&
|
418
|
+
((defined? ::Asciidoctor::PDF::Optimizer) || !(Helpers.require_library OptimizerRequirePath, 'rghost', :warn).nil?)
|
419
|
+
@optimize = (optimize.include? ',') ?
|
420
|
+
([:quality, :compliance].zip (optimize.split ',', 2)).to_h :
|
421
|
+
((optimize.include? '/') ? { compliance: optimize } : { quality: optimize })
|
422
|
+
fit_trim_box if @optimize[:compliance]&.start_with? 'PDF/X'
|
423
|
+
else
|
424
|
+
@optimize = nil
|
416
425
|
end
|
417
426
|
allocate_scratch_prototype
|
418
427
|
self
|
@@ -717,7 +726,7 @@ module Asciidoctor
|
|
717
726
|
when 'page'
|
718
727
|
pagenums = term.dests.uniq {|dest| dest[:page] }.map {|dest| %(<a anchor="#{dest[:anchor]}">#{dest[:page]}</a>) }
|
719
728
|
when 'range'
|
720
|
-
first_anchor_per_page = term.dests.
|
729
|
+
first_anchor_per_page = {}.tap {|accum| term.dests.each {|dest| accum[dest[:page]] ||= dest[:anchor] } }
|
721
730
|
pagenums = (consolidate_ranges first_anchor_per_page.keys).map do |range|
|
722
731
|
anchor = first_anchor_per_page[(range.include? '-') ? (range.partition '-')[0] : range]
|
723
732
|
%(<a anchor="#{anchor}">#{range}</a>)
|
@@ -814,7 +823,7 @@ module Asciidoctor
|
|
814
823
|
if (text_align = resolve_text_align_from_role (roles = node.roles), query_theme: true, remove_predefined: true)
|
815
824
|
prose_opts[:align] = text_align
|
816
825
|
end
|
817
|
-
role_keys = roles.map {|role| %(role_#{role})
|
826
|
+
role_keys = roles.map {|role| %(role_#{role}) } unless roles.empty?
|
818
827
|
if (text_indent = @theme.prose_text_indent) > 0 ||
|
819
828
|
((text_indent = @theme.prose_text_indent_inner) > 0 && node.previous_sibling&.context == :paragraph)
|
820
829
|
prose_opts[:indent_paragraphs] = text_indent
|
@@ -1081,7 +1090,7 @@ module Asciidoctor
|
|
1081
1090
|
highlight_lines = nil
|
1082
1091
|
else
|
1083
1092
|
pg_highlight_bg_color = pg_block_styles[:highlight_background_color]
|
1084
|
-
highlight_lines = highlight_lines.
|
1093
|
+
highlight_lines = {}.tap {|accum| highlight_lines.each {|linenum| accum[linenum] = pg_highlight_bg_color } }
|
1085
1094
|
end
|
1086
1095
|
end
|
1087
1096
|
if (node.option? 'linenums') || (node.attr? 'linenums')
|
@@ -1110,17 +1119,17 @@ module Asciidoctor
|
|
1110
1119
|
end
|
1111
1120
|
if (srclang = node.attr 'language')
|
1112
1121
|
if srclang.include? '?'
|
1113
|
-
if (lexer = ::Rouge::Lexer.find_fancy srclang)
|
1122
|
+
if (lexer = ::Rouge::Lexer.find_fancy srclang)&.tag == 'php' && !(node.option? 'mixed') && !((lexer_opts = lexer.options).key? 'start_inline')
|
1114
1123
|
lexer = lexer.class.new lexer_opts.merge 'start_inline' => true
|
1115
1124
|
end
|
1116
|
-
elsif (lexer = ::Rouge::Lexer.find srclang)
|
1117
|
-
lexer = lexer.new start_inline: true
|
1125
|
+
elsif (lexer = ::Rouge::Lexer.find srclang)&.tag == 'php' && !(node.option? 'mixed')
|
1126
|
+
lexer = lexer.new start_inline: true
|
1118
1127
|
end
|
1119
1128
|
end
|
1120
1129
|
lexer ||= ::Rouge::Lexers::PlainText
|
1121
1130
|
source_string, conum_mapping = extract_conums source_string if callouts_enabled
|
1122
1131
|
if (node.attr? 'highlight') && !(hl_lines = (node.resolve_lines_to_highlight source_string, (node.attr 'highlight'))).empty?
|
1123
|
-
formatter_opts[:highlight_lines] = hl_lines.
|
1132
|
+
formatter_opts[:highlight_lines] = {}.tap {|accum| hl_lines.each {|linenum| accum[linenum] = true } }
|
1124
1133
|
end
|
1125
1134
|
fragments = formatter.format (lexer.lex source_string), formatter_opts rescue [text: source_string]
|
1126
1135
|
source_chunks = conum_mapping ? (restore_conums fragments, conum_mapping) : fragments
|
@@ -1205,10 +1214,10 @@ module Asciidoctor
|
|
1205
1214
|
b_left_width = nil
|
1206
1215
|
b_width = nil if (b_width = @theme[%(#{category}_border_width)]) == 0
|
1207
1216
|
end
|
1208
|
-
if (attribution =
|
1217
|
+
if (attribution = node.attr 'attribution')
|
1209
1218
|
# NOTE: temporary workaround to allow bare & to be used without having to wrap value in single quotes
|
1210
1219
|
attribution = escape_amp attribution if attribution.include? '&'
|
1211
|
-
if (citetitle = node.attr 'citetitle')
|
1220
|
+
if (citetitle = node.attr 'citetitle')&.include? '&'
|
1212
1221
|
citetitle = escape_amp citetitle
|
1213
1222
|
end
|
1214
1223
|
end
|
@@ -1396,7 +1405,7 @@ module Asciidoctor
|
|
1396
1405
|
end
|
1397
1406
|
theme_margin :prose, :bottom, (next_enclosed_block actual_node) #unless actual_node.nested?
|
1398
1407
|
when 'qanda'
|
1399
|
-
@list_numerals <<
|
1408
|
+
@list_numerals << 1
|
1400
1409
|
convert_list node
|
1401
1410
|
@list_numerals.pop
|
1402
1411
|
else
|
@@ -1760,7 +1769,7 @@ module Asciidoctor
|
|
1760
1769
|
advance_page
|
1761
1770
|
available_h = cursor - caption_h
|
1762
1771
|
end
|
1763
|
-
rendered_w
|
1772
|
+
rendered_w = (image_info.calc_image_dimensions height: (rendered_h = available_h))[0] if rendered_h > available_h
|
1764
1773
|
end
|
1765
1774
|
add_dest_for_block node if node.id
|
1766
1775
|
# NOTE: workaround to fix Prawn not adding fill and stroke commands on page that only has an image;
|
@@ -2167,6 +2176,7 @@ module Asciidoctor
|
|
2167
2176
|
|
2168
2177
|
left_padding = right_padding = nil
|
2169
2178
|
table table_data, table_settings do
|
2179
|
+
@column_widths = column_widths unless column_widths.empty?
|
2170
2180
|
# NOTE: call width to capture resolved table width
|
2171
2181
|
table_width = width
|
2172
2182
|
@pdf.ink_table_caption node, alignment, table_width, caption_max_width if node.title? && caption_end == :top
|
@@ -3261,64 +3271,70 @@ module Asciidoctor
|
|
3261
3271
|
end
|
3262
3272
|
end
|
3263
3273
|
|
3264
|
-
colspec_dict =
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3268
|
-
|
3269
|
-
|
3270
|
-
|
3271
|
-
|
3272
|
-
|
3273
|
-
|
3274
|
-
|
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
|
3274
|
+
colspec_dict = {}.tap do |acc|
|
3275
|
+
PageSides.each do |side|
|
3276
|
+
side_trim_content_width = trim_content_width[side]
|
3277
|
+
if (custom_colspecs = @theme[%(#{periphery}_#{side}_columns)] || @theme[%(#{periphery}_columns)])
|
3278
|
+
case (colspecs = (custom_colspecs.to_s.tr ',', ' ').split).size
|
3279
|
+
when 0, 1
|
3280
|
+
colspecs = { left: '0', center: colspecs[0] || '100', right: '0' }
|
3281
|
+
when 2
|
3282
|
+
colspecs = { left: colspecs[0], center: '0', right: colspecs[1] }
|
3283
|
+
else # 3
|
3284
|
+
colspecs = { left: colspecs[0], center: colspecs[1], right: colspecs[2] }
|
3283
3285
|
end
|
3284
|
-
tot_width
|
3285
|
-
|
3286
|
-
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3290
|
-
|
3291
|
-
|
3292
|
-
|
3293
|
-
|
3294
|
-
|
3295
|
-
|
3296
|
-
|
3286
|
+
tot_width = 0
|
3287
|
+
side_colspecs = {}.tap do |accum|
|
3288
|
+
colspecs.each do |col, spec|
|
3289
|
+
if (alignment_char = spec.chr).to_i.to_s == alignment_char
|
3290
|
+
alignment = :left
|
3291
|
+
rel_width = spec.to_f
|
3292
|
+
else
|
3293
|
+
alignment = AlignmentTable[alignment_char]
|
3294
|
+
rel_width = (spec.slice 1, spec.length).to_f
|
3295
|
+
end
|
3296
|
+
tot_width += rel_width
|
3297
|
+
accum[col] = { align: alignment, width: rel_width, x: 0 }
|
3298
|
+
end
|
3299
|
+
end
|
3300
|
+
# QUESTION: should we allow the columns to overlap (capping width at 100%)?
|
3301
|
+
side_colspecs.each {|_, colspec| colspec[:width] = (colspec[:width] / tot_width) * side_trim_content_width }
|
3302
|
+
side_colspecs[:right][:x] = (side_colspecs[:center][:x] = side_colspecs[:left][:width]) + side_colspecs[:center][:width]
|
3303
|
+
acc[side] = side_colspecs
|
3304
|
+
else
|
3305
|
+
acc[side] = {
|
3306
|
+
left: { align: :left, width: side_trim_content_width, x: 0 },
|
3307
|
+
center: { align: :center, width: side_trim_content_width, x: 0 },
|
3308
|
+
right: { align: :right, width: side_trim_content_width, x: 0 },
|
3309
|
+
}
|
3310
|
+
end
|
3297
3311
|
end
|
3298
3312
|
end
|
3299
3313
|
|
3300
|
-
content_dict =
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3309
|
-
|
3310
|
-
|
3311
|
-
|
3314
|
+
content_dict = {}.tap do |acc|
|
3315
|
+
PageSides.each do |side|
|
3316
|
+
side_content = {}
|
3317
|
+
ColumnPositions.each do |position|
|
3318
|
+
next if (val = @theme[%(#{periphery}_#{side}_#{position}_content)]).nil_or_empty?
|
3319
|
+
val = val.to_s unless ::String === val
|
3320
|
+
if (val.include? ':') && val =~ ImageAttributeValueRx
|
3321
|
+
attrlist = $2
|
3322
|
+
image_attrs = (AttributeList.new attrlist).parse %w(alt width)
|
3323
|
+
image_path, image_format = ::Asciidoctor::Image.target_and_format $1, image_attrs
|
3324
|
+
if (image_path = resolve_image_path doc, image_path, image_format, @themesdir) && (::File.readable? image_path)
|
3325
|
+
image_opts = resolve_image_options image_path, image_format, image_attrs, container_size: [colspec_dict[side][position][:width], trim_content_height[side]]
|
3326
|
+
side_content[position] = [image_path, image_opts, image_attrs['link']]
|
3327
|
+
else
|
3328
|
+
# NOTE: allows inline image handler to report invalid reference and replace with alt text
|
3329
|
+
side_content[position] = %(image:#{image_path}[#{attrlist}])
|
3330
|
+
end
|
3312
3331
|
else
|
3313
|
-
|
3314
|
-
side_content[position] = %(image:#{image_path}[#{attrlist}])
|
3332
|
+
side_content[position] = val
|
3315
3333
|
end
|
3316
|
-
else
|
3317
|
-
side_content[position] = val
|
3318
3334
|
end
|
3319
|
-
end
|
3320
3335
|
|
3321
|
-
|
3336
|
+
acc[side] = side_content
|
3337
|
+
end
|
3322
3338
|
end
|
3323
3339
|
|
3324
3340
|
if (trim_bg_color = trim_styles[:bg_color]) || trim_bg_image || trim_border_width > 0
|
@@ -3601,7 +3617,6 @@ module Asciidoctor
|
|
3601
3617
|
end
|
3602
3618
|
end
|
3603
3619
|
|
3604
|
-
# TODO: prevent content from spilling to next page
|
3605
3620
|
theme_font :title_page do
|
3606
3621
|
if (title_top = @theme.title_page_title_top)
|
3607
3622
|
@y = resolve_top title_top
|
@@ -3866,18 +3881,17 @@ module Asciidoctor
|
|
3866
3881
|
|
3867
3882
|
def register_fonts font_catalog, fonts_dir
|
3868
3883
|
return unless font_catalog
|
3869
|
-
dirs = (fonts_dir.split ValueSeparatorRx, -1).map
|
3870
|
-
dir == 'GEM_FONTS_DIR' || dir.empty? ? ThemeLoader::FontsDir : dir
|
3871
|
-
end
|
3884
|
+
dirs = (fonts_dir.split ValueSeparatorRx, -1).map {|dir| dir == 'GEM_FONTS_DIR' || dir.empty? ? ThemeLoader::FontsDir : dir }
|
3872
3885
|
font_catalog.each do |key, styles|
|
3873
|
-
|
3874
|
-
|
3875
|
-
|
3876
|
-
|
3886
|
+
register_font key => ({}.tap do |accum|
|
3887
|
+
styles.each do |style, path|
|
3888
|
+
found = dirs.any? do |dir|
|
3889
|
+
resolved_font_path = font_path path, dir
|
3890
|
+
accum[style.to_sym] = resolved_font_path if ::File.readable? resolved_font_path
|
3891
|
+
end
|
3892
|
+
raise ::Errno::ENOENT, ((File.absolute_path? path) ? %(#{path} not found) : %(#{path} not found in #{fonts_dir.gsub ValueSeparatorRx, ' or '})) unless found
|
3877
3893
|
end
|
3878
|
-
|
3879
|
-
end
|
3880
|
-
register_font key => styles
|
3894
|
+
end)
|
3881
3895
|
end
|
3882
3896
|
end
|
3883
3897
|
|
@@ -4397,13 +4411,8 @@ module Asciidoctor
|
|
4397
4411
|
pdf_doc.render_file target
|
4398
4412
|
# QUESTION: restore attributes first?
|
4399
4413
|
@pdfmark&.generate_file target
|
4400
|
-
if (
|
4401
|
-
|
4402
|
-
quality, compliance = quality.split ',', 2
|
4403
|
-
elsif quality.include? '/'
|
4404
|
-
quality, compliance = nil, quality
|
4405
|
-
end
|
4406
|
-
(Optimizer.new quality, pdf_doc.min_version, compliance).optimize_file target
|
4414
|
+
if (optimize = @optimize)
|
4415
|
+
(Optimizer.new optimize[:quality], pdf_doc.min_version, optimize[:compliance]).optimize_file target
|
4407
4416
|
end
|
4408
4417
|
to_file = true
|
4409
4418
|
end
|
@@ -4578,14 +4587,16 @@ module Asciidoctor
|
|
4578
4587
|
def consolidate_ranges nums
|
4579
4588
|
if nums.size > 1
|
4580
4589
|
prev = nil
|
4581
|
-
|
4590
|
+
accum = []
|
4591
|
+
nums.each do |num|
|
4582
4592
|
if prev && (prev.to_i + 1) == num.to_i
|
4583
4593
|
accum[-1][1] = num
|
4584
4594
|
else
|
4585
4595
|
accum << [num]
|
4586
4596
|
end
|
4587
4597
|
prev = num
|
4588
|
-
end
|
4598
|
+
end
|
4599
|
+
accum.map {|range| range.join '-' }
|
4589
4600
|
else
|
4590
4601
|
nums
|
4591
4602
|
end
|
@@ -4628,6 +4639,15 @@ module Asciidoctor
|
|
4628
4639
|
(max_height = bounds.height) < preferred_size ? max_height : preferred_size
|
4629
4640
|
end
|
4630
4641
|
|
4642
|
+
def fit_trim_box page_ = page
|
4643
|
+
page_.dictionary.data[:TrimBox].tap do |trim_box|
|
4644
|
+
trim_box[0] += 1e-4
|
4645
|
+
trim_box[1] += 1e-4
|
4646
|
+
trim_box[2] -= 1e-4
|
4647
|
+
trim_box[3] -= 1e-4
|
4648
|
+
end
|
4649
|
+
end
|
4650
|
+
|
4631
4651
|
def font_path font_file, fonts_dir
|
4632
4652
|
# resolve relative to built-in font dir unless path is absolute
|
4633
4653
|
::File.absolute_path font_file, fonts_dir
|
@@ -4930,14 +4950,16 @@ module Asciidoctor
|
|
4930
4950
|
result = yield
|
4931
4951
|
else
|
4932
4952
|
email = nil
|
4933
|
-
original_attrs =
|
4934
|
-
|
4935
|
-
|
4936
|
-
|
4937
|
-
|
4938
|
-
|
4939
|
-
|
4940
|
-
|
4953
|
+
original_attrs = {}.tap do |accum|
|
4954
|
+
AuthorAttributeNames.each do |prop_name, attr_name|
|
4955
|
+
accum[attr_name] = doc.attr attr_name
|
4956
|
+
if (val = author[prop_name])
|
4957
|
+
doc.set_attr attr_name, val
|
4958
|
+
# NOTE: email attribute could be a url
|
4959
|
+
email = val if prop_name == :email
|
4960
|
+
else
|
4961
|
+
doc.remove_attr attr_name
|
4962
|
+
end
|
4941
4963
|
end
|
4942
4964
|
end
|
4943
4965
|
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.
|
7
|
+
Prawn::Icon::Compatibility.prepend (::Module.new { def warning *_args; end })
|
8
8
|
|
9
9
|
module Asciidoctor
|
10
10
|
module Prawn
|
@@ -431,15 +431,19 @@ module Asciidoctor
|
|
431
431
|
|
432
432
|
# NOTE: override built-in fill_formatted_text_box to insert leading before second line when :first_line is true
|
433
433
|
def fill_formatted_text_box text, options
|
434
|
-
if (initial_gap = options[:initial_gap]) &&
|
434
|
+
if (initial_gap = options[:initial_gap]) && !text.empty? && text[0][:from_page] != page_number
|
435
435
|
self.y -= initial_gap
|
436
436
|
end
|
437
437
|
merge_text_box_positioning_options options
|
438
438
|
box = ::Prawn::Text::Formatted::Box.new text, options
|
439
|
-
|
439
|
+
remaining_fragments = box.render
|
440
440
|
@no_text_printed = box.nothing_printed?
|
441
441
|
@all_text_printed = box.everything_printed?
|
442
|
-
|
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
|
443
447
|
|
444
448
|
if @final_gap || (options[:first_line] && !(@no_text_printed || @all_text_printed))
|
445
449
|
self.y -= box.height + box.line_gap + box.leading
|
@@ -447,7 +451,7 @@ module Asciidoctor
|
|
447
451
|
self.y -= box.height
|
448
452
|
end
|
449
453
|
|
450
|
-
|
454
|
+
remaining_fragments
|
451
455
|
end
|
452
456
|
|
453
457
|
# NOTE: override built-in draw_indented_formatted_line to set first_line flag
|
@@ -483,7 +487,13 @@ module Asciidoctor
|
|
483
487
|
else
|
484
488
|
remaining_fragments = box.render dry_run: true
|
485
489
|
end
|
486
|
-
remaining_fragments.empty?
|
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
|
487
497
|
if first_line_text_transform
|
488
498
|
# NOTE: applying text transform here could alter the wrapping, so isolate first line and shrink it to fit
|
489
499
|
first_line_text = (box.instance_variable_get :@printed_lines)[0]
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
module Prawn::Text::Formatted::ProtectBottomGutter
|
4
4
|
def enough_height_for_this_line?
|
5
|
-
|
6
|
-
|
7
|
-
|
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.
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
(
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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] =
|
280
|
-
|
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).
|
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] =
|
163
|
-
|
164
|
-
|
165
|
-
|
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)
|
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.
|
4
|
+
version: 2.0.3
|
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-
|
12
|
+
date: 2022-05-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|