asciidoctor-pdf 2.1.5 → 2.3.0
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 +4 -4
- data/CHANGELOG.adoc +71 -8
- data/README.adoc +1 -1
- data/bin/asciidoctor-pdf +26 -7
- data/bin/asciidoctor-pdf-optimize +1 -2
- data/data/themes/base-theme.yml +2 -2
- data/data/themes/default-theme.yml +7 -30
- data/lib/asciidoctor/pdf/converter.rb +232 -154
- data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +5 -0
- data/lib/asciidoctor/pdf/ext/prawn/document/column_box.rb +4 -0
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +10 -4
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +11 -0
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/line_wrap.rb +42 -0
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +5 -2
- data/lib/asciidoctor/pdf/sanitizer.rb +7 -3
- data/lib/asciidoctor/pdf/theme_loader.rb +10 -14
- data/lib/asciidoctor/pdf/version.rb +1 -1
- metadata +3 -2
@@ -46,8 +46,9 @@ module Asciidoctor
|
|
46
46
|
tip: { name: 'far-lightbulb', stroke_color: '111111', size: 24 },
|
47
47
|
warning: { name: 'fas-exclamation-triangle', stroke_color: 'BF6900', size: 24 },
|
48
48
|
}
|
49
|
-
TextAlignmentNames =
|
50
|
-
|
49
|
+
TextAlignmentNames = { 'justify' => true, 'left' => true, 'center' => true, 'right' => true }
|
50
|
+
IndentableTextAlignments = { justify: true, left: true }
|
51
|
+
TextAlignmentRoles = { 'text-justify' => true, 'text-left' => true, 'text-center' => true, 'text-right' => true }
|
51
52
|
TextDecorationStyleTable = { 'underline' => :underline, 'line-through' => :strikethrough }
|
52
53
|
FontKerningTable = { 'normal' => true, 'none' => false }
|
53
54
|
BlockFloatNames = %w(left right)
|
@@ -102,6 +103,7 @@ module Asciidoctor
|
|
102
103
|
'filled' => (?\u2776..?\u277f).to_a + (?\u24eb..?\u24f4).to_a,
|
103
104
|
}
|
104
105
|
TypographicQuotes = %w(“ ” ‘ ’)
|
106
|
+
InlineFormatSniffRx = /[<&]/
|
105
107
|
SimpleAttributeRefRx = /(?<!\\)\{\w+(?:-\w+)*\}/
|
106
108
|
MeasurementRxt = '\\d+(?:\\.\\d+)?(?:in|cm|mm|p[txc])?'
|
107
109
|
MeasurementPartsRx = /^(\d+(?:\.\d+)?)(in|mm|cm|p[txc])?$/
|
@@ -160,11 +162,11 @@ module Asciidoctor
|
|
160
162
|
doc.promote_preface_block
|
161
163
|
init_pdf doc
|
162
164
|
# set default value for outline, outline-title, and pagenums attributes if not otherwise set
|
163
|
-
doc.attributes['outline'] = ''
|
164
|
-
doc.attributes['outline-title'] = ''
|
165
|
-
doc.attributes['pagenums'] = ''
|
165
|
+
doc.attributes['outline'] = '' if doc.attr_unspecified? 'outline'
|
166
|
+
doc.attributes['outline-title'] = '' if doc.attr_unspecified? 'outline-title'
|
167
|
+
doc.attributes['pagenums'] = '' if doc.attr_unspecified? 'pagenums'
|
166
168
|
|
167
|
-
on_page_create(&(method :init_page))
|
169
|
+
on_page_create(&(method :init_page).curry[doc])
|
168
170
|
|
169
171
|
marked_page_number = page_number
|
170
172
|
# NOTE: a new page will already be started (page_number = 2) if the front cover image is a PDF
|
@@ -179,7 +181,7 @@ module Asciidoctor
|
|
179
181
|
end
|
180
182
|
start_new_page
|
181
183
|
else
|
182
|
-
@
|
184
|
+
@page_margin[:cover] = @page_margin[page.layout][:recto] if @media == 'prepress' && page_number == 0
|
183
185
|
start_new_page unless page&.empty? # rubocop:disable Lint/SafeNavigationWithEmpty
|
184
186
|
# NOTE: the base font must be set before any content is written to the main or scratch document
|
185
187
|
# this method is called inside ink_title_page if the title page is active
|
@@ -200,19 +202,24 @@ module Asciidoctor
|
|
200
202
|
if (insert_toc = (doc.attr? 'toc') && !((toc_placement = doc.attr 'toc-placement') == 'macro' || toc_placement == 'preamble') && !(get_entries_for_toc doc).empty?)
|
201
203
|
start_new_page if @ppbook && verso_page?
|
202
204
|
add_dest_for_block doc, id: 'toc', y: (at_page_top? ? page_height : nil)
|
203
|
-
@toc_extent = allocate_toc doc, toc_num_levels, cursor, title_page_on
|
205
|
+
@toc_extent = allocate_toc doc, toc_num_levels, cursor, (title_page_on && theme.toc_break_after != 'auto')
|
204
206
|
else
|
205
207
|
@toc_extent = nil
|
206
208
|
end
|
207
209
|
|
208
|
-
|
210
|
+
if @ppbook && verso_page? && !(((next_block = doc.first_child)&.context == :preamble ? next_block.first_child : next_block)&.option? 'nonfacing')
|
211
|
+
min_start_at = 0
|
212
|
+
start_new_page
|
213
|
+
else
|
214
|
+
min_start_at = 1
|
215
|
+
end
|
209
216
|
|
210
217
|
if title_page_on
|
211
218
|
zero_page_offset = has_front_cover ? 1 : 0
|
212
219
|
first_page_offset = has_title_page ? zero_page_offset.next : zero_page_offset
|
213
220
|
body_offset = (body_start_page_number = page_number) - 1
|
214
221
|
if ::Integer === (running_content_start_at = @theme.running_content_start_at)
|
215
|
-
running_content_body_offset = body_offset + [running_content_start_at.pred,
|
222
|
+
running_content_body_offset = body_offset + [running_content_start_at.pred, min_start_at.pred].max
|
216
223
|
running_content_start_at = 'body'
|
217
224
|
else
|
218
225
|
running_content_body_offset = body_offset
|
@@ -226,7 +233,7 @@ module Asciidoctor
|
|
226
233
|
end
|
227
234
|
end
|
228
235
|
if ::Integer === (page_numbering_start_at = @theme.page_numbering_start_at)
|
229
|
-
page_numbering_body_offset = body_offset + [page_numbering_start_at.pred,
|
236
|
+
page_numbering_body_offset = body_offset + [page_numbering_start_at.pred, min_start_at.pred].max
|
230
237
|
page_numbering_start_at = 'body'
|
231
238
|
else
|
232
239
|
page_numbering_body_offset = body_offset
|
@@ -351,7 +358,6 @@ module Asciidoctor
|
|
351
358
|
@cache_uri = doc.attr? 'cache-uri'
|
352
359
|
@jail_dir = doc.safe < ::Asciidoctor::SafeMode::SAFE ? nil : doc.base_dir
|
353
360
|
@media ||= doc.attr 'media', 'screen'
|
354
|
-
@page_margin_by_side = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin), cover: page_margin }
|
355
361
|
case doc.attr 'pdf-folio-placement', (@media == 'prepress' ? 'physical' : 'virtual')
|
356
362
|
when 'physical'
|
357
363
|
@folio_placement = { basis: :physical }
|
@@ -362,6 +368,13 @@ module Asciidoctor
|
|
362
368
|
else
|
363
369
|
@folio_placement = { basis: :virtual }
|
364
370
|
end
|
371
|
+
@page_margin = { cover: page_margin }
|
372
|
+
@page_margin[:portrait] = @page_margin[:landscape] = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin) }
|
373
|
+
if (rotated_page_margin = resolve_page_margin (doc.attr 'pdf-page-margin-rotated') || theme.page_margin_rotated)
|
374
|
+
rotated_page_margin = expand_margin_value rotated_page_margin
|
375
|
+
@edge_shorthand_cache = nil
|
376
|
+
@page_margin[PageLayouts[(PageLayouts.index page.layout) - 1]] = { recto: rotated_page_margin, verso: rotated_page_margin.dup }
|
377
|
+
end
|
365
378
|
if @media == 'prepress'
|
366
379
|
@ppbook = doc.doctype == 'book'
|
367
380
|
if (page_margin_outer = theme.page_margin_outer)
|
@@ -373,17 +386,7 @@ module Asciidoctor
|
|
373
386
|
else
|
374
387
|
@ppbook = nil
|
375
388
|
end
|
376
|
-
|
377
|
-
@page_bg_image = { verso: bg_image, recto: bg_image }
|
378
|
-
else
|
379
|
-
@page_bg_image = { verso: nil, recto: nil }
|
380
|
-
end
|
381
|
-
if (bg_image = resolve_background_image doc, theme, 'page-background-image-verso')
|
382
|
-
@page_bg_image[:verso] = bg_image[0] && bg_image
|
383
|
-
end
|
384
|
-
if (bg_image = resolve_background_image doc, theme, 'page-background-image-recto')
|
385
|
-
@page_bg_image[:recto] = bg_image[0] && bg_image
|
386
|
-
end
|
389
|
+
@page_bg_image = {}
|
387
390
|
@page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
|
388
391
|
# QUESTION: should ThemeLoader handle registering fonts instead?
|
389
392
|
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
|
@@ -393,11 +396,10 @@ module Asciidoctor
|
|
393
396
|
@font_scale = 1
|
394
397
|
@font_color = theme.base_font_color
|
395
398
|
@text_decoration_width = theme.base_text_decoration_width
|
396
|
-
@base_text_align = (text_align = doc.attr 'text-align') &&
|
399
|
+
@base_text_align = (text_align = doc.attr 'text-align') && TextAlignmentNames[text_align] ? text_align : theme.base_text_align
|
397
400
|
@base_line_height = theme.base_line_height
|
398
401
|
@cjk_line_breaks = doc.attr? 'scripts', 'cjk'
|
399
|
-
if (hyphen_lang = (doc.attr 'hyphens') ||
|
400
|
-
(((doc.attribute_locked? 'hyphens') || ((doc.instance_variable_get :@attributes_modified).include? 'hyphens')) ? nil : @theme.base_hyphens)) &&
|
402
|
+
if (hyphen_lang = (doc.attr 'hyphens') || ((doc.attr_unspecified? 'hyphens') ? @theme.base_hyphens : nil)) &&
|
401
403
|
((defined? ::Text::Hyphen::VERSION) || !(Helpers.require_library 'text/hyphen', 'text-hyphen', :warn).nil?)
|
402
404
|
hyphen_lang = doc.attr 'lang' if !(::String === hyphen_lang) || hyphen_lang.empty?
|
403
405
|
hyphen_lang = 'en_us' if hyphen_lang.nil_or_empty? || hyphen_lang == 'en'
|
@@ -435,34 +437,7 @@ module Asciidoctor
|
|
435
437
|
end
|
436
438
|
|
437
439
|
def build_pdf_options doc, theme
|
438
|
-
|
439
|
-
when ::Array
|
440
|
-
if page_margin.empty?
|
441
|
-
page_margin = nil
|
442
|
-
else
|
443
|
-
page_margin = page_margin.slice 0, 4 if page_margin.length > 4
|
444
|
-
page_margin = page_margin.map {|v| ::Numeric === v ? v : (str_to_pt v.to_s) }
|
445
|
-
end
|
446
|
-
when ::Numeric
|
447
|
-
page_margin = [page_margin]
|
448
|
-
when ::String
|
449
|
-
if page_margin.empty?
|
450
|
-
page_margin = nil
|
451
|
-
elsif (page_margin.start_with? '[') && (page_margin.end_with? ']')
|
452
|
-
if (page_margin = (page_margin.slice 1, page_margin.length - 2).rstrip).empty?
|
453
|
-
page_margin = nil
|
454
|
-
else
|
455
|
-
if (page_margin = page_margin.split ',', -1).length > 4
|
456
|
-
page_margin = page_margin.slice 0, 4
|
457
|
-
end
|
458
|
-
page_margin = page_margin.map {|v| str_to_pt v.rstrip }
|
459
|
-
end
|
460
|
-
else
|
461
|
-
page_margin = [(str_to_pt page_margin)]
|
462
|
-
end
|
463
|
-
else
|
464
|
-
page_margin = nil
|
465
|
-
end
|
440
|
+
page_margin = resolve_page_margin (doc.attr 'pdf-page-margin') || theme.page_margin
|
466
441
|
|
467
442
|
if (doc.attr? 'pdf-page-size') && PageSizeRx =~ (doc.attr 'pdf-page-size')
|
468
443
|
# e.g, [8.5in, 11in]
|
@@ -560,8 +535,10 @@ module Asciidoctor
|
|
560
535
|
elsif (theme_name = doc.attr 'pdf-theme')
|
561
536
|
theme = ThemeLoader.load_theme theme_name, (user_themesdir = (doc.attr 'pdf-themesdir')&.sub '{docdir}', (doc.attr 'docdir'))
|
562
537
|
@themesdir = theme.__dir__
|
563
|
-
|
538
|
+
elsif (doc.attr 'media', 'screen') == 'screen'
|
564
539
|
@themesdir = (theme = ThemeLoader.load_theme).__dir__
|
540
|
+
else
|
541
|
+
@themesdir = (theme = ThemeLoader.load_theme 'default-for-print').__dir__
|
565
542
|
end
|
566
543
|
prepare_theme theme
|
567
544
|
rescue
|
@@ -604,6 +581,7 @@ module Asciidoctor
|
|
604
581
|
theme.code_linenum_font_color ||= '999999'
|
605
582
|
theme.callout_list_margin_top_after_code ||= 0
|
606
583
|
theme.role_unresolved_font_color ||= 'FF0000'
|
584
|
+
theme.footnotes_margin_top ||= 'auto'
|
607
585
|
theme.footnotes_item_spacing ||= 0
|
608
586
|
theme.index_columns ||= 2
|
609
587
|
theme.index_column_gap ||= theme.base_font_size
|
@@ -768,22 +746,16 @@ module Asciidoctor
|
|
768
746
|
pagenums = consolidate_ranges term.dests.map {|dest| dest[:page] }.uniq
|
769
747
|
end
|
770
748
|
pagenums.each do |pagenum|
|
771
|
-
|
772
|
-
|
773
|
-
if ::String === pagenum
|
774
|
-
term_fragments[-1] = prev_fragment.merge text: %(#{prev_fragment[:text]}, #{pagenum})
|
775
|
-
next
|
776
|
-
else
|
777
|
-
term_fragments[-1] = prev_fragment.merge text: %(#{prev_fragment[:text]}, )
|
778
|
-
end
|
749
|
+
if ::String === pagenum
|
750
|
+
term_fragments << ({ text: %(, #{pagenum}) })
|
779
751
|
else
|
780
|
-
term_fragments <<
|
752
|
+
term_fragments << { text: ', ' }
|
753
|
+
term_fragments << pagenum
|
781
754
|
end
|
782
|
-
term_fragments << (::String === pagenum ? { text: pagenum } : pagenum)
|
783
755
|
end
|
784
756
|
end
|
785
757
|
subterm_indent = @theme.description_list_description_indent
|
786
|
-
typeset_formatted_text term_fragments, (calc_line_metrics @base_line_height), align: :left, color: @font_color, hanging_indent: subterm_indent * 2
|
758
|
+
typeset_formatted_text term_fragments, (calc_line_metrics @base_line_height), align: :left, color: @font_color, hanging_indent: subterm_indent * 2, consolidate: true
|
787
759
|
indent subterm_indent do
|
788
760
|
term.subterms.each do |subterm|
|
789
761
|
convert_index_term subterm, pagenum_sequence_style
|
@@ -809,10 +781,7 @@ module Asciidoctor
|
|
809
781
|
ink_prose node.title, align: (@theme.abstract_title_text_align || @base_text_align).to_sym, margin_top: @theme.heading_margin_top, margin_bottom: @theme.heading_margin_bottom, line_height: (@theme.heading_line_height || @theme.base_line_height)
|
810
782
|
end if node.title?
|
811
783
|
theme_font :abstract do
|
812
|
-
prose_opts = { align: (@theme.abstract_text_align || @base_text_align).to_sym, hyphenate: true }
|
813
|
-
if (text_indent = @theme.prose_text_indent) > 0
|
814
|
-
prose_opts[:indent_paragraphs] = text_indent
|
815
|
-
end
|
784
|
+
prose_opts = { align: (@theme.abstract_text_align || @base_text_align).to_sym, hyphenate: true, margin_bottom: 0 }
|
816
785
|
# FIXME: allow theme to control more first line options
|
817
786
|
if (line1_font_style = @theme.abstract_first_line_font_style&.to_sym) && line1_font_style != font_style
|
818
787
|
case line1_font_style
|
@@ -833,14 +802,11 @@ module Asciidoctor
|
|
833
802
|
prose_opts[:first_line_options] = first_line_options if first_line_options
|
834
803
|
# FIXME: make this cleaner!!
|
835
804
|
if node.blocks?
|
836
|
-
last_block = node.last_child
|
837
805
|
node.blocks.each do |child|
|
838
806
|
if child.context == :paragraph
|
839
807
|
child.document.playback_attributes child.attributes
|
840
|
-
|
841
|
-
ink_prose child.content, ((text_align = resolve_text_align_from_role child.roles) ? (prose_opts.merge align: text_align) : prose_opts.dup)
|
808
|
+
convert_paragraph child, prose_opts.dup
|
842
809
|
prose_opts.delete :first_line_options
|
843
|
-
prose_opts.delete :margin_bottom
|
844
810
|
else
|
845
811
|
# FIXME: this could do strange things if the wrong kind of content shows up
|
846
812
|
child.convert
|
@@ -850,7 +816,10 @@ module Asciidoctor
|
|
850
816
|
if (text_align = resolve_text_align_from_role node.roles)
|
851
817
|
prose_opts[:align] = text_align
|
852
818
|
end
|
853
|
-
|
819
|
+
if IndentableTextAlignments[prose_opts[:align]] && (text_indent = @theme.prose_text_indent) > 0
|
820
|
+
prose_opts[:indent_paragraphs] = text_indent
|
821
|
+
end
|
822
|
+
ink_prose string, prose_opts
|
854
823
|
end
|
855
824
|
end
|
856
825
|
end
|
@@ -859,16 +828,19 @@ module Asciidoctor
|
|
859
828
|
theme_margin :block, :bottom, (next_enclosed_block node)
|
860
829
|
end
|
861
830
|
|
862
|
-
def convert_paragraph node
|
831
|
+
def convert_paragraph node, opts = nil
|
863
832
|
add_dest_for_block node if node.id
|
864
833
|
|
865
|
-
prose_opts = { margin_bottom: 0, hyphenate: true }
|
834
|
+
prose_opts = opts || { margin_bottom: 0, hyphenate: true }
|
866
835
|
if (text_align = resolve_text_align_from_role (roles = node.roles), query_theme: true, remove_predefined: true)
|
867
836
|
prose_opts[:align] = text_align
|
837
|
+
else
|
838
|
+
text_align = @base_text_align.to_sym
|
868
839
|
end
|
869
840
|
role_keys = roles.map {|role| %(role_#{role}) } unless roles.empty?
|
870
|
-
if
|
871
|
-
((text_indent = @theme.
|
841
|
+
if IndentableTextAlignments[text_align] &&
|
842
|
+
((text_indent = @theme.prose_text_indent) > 0 ||
|
843
|
+
((text_indent = @theme.prose_text_indent_inner) > 0 && node.previous_sibling&.context == :paragraph))
|
872
844
|
prose_opts[:indent_paragraphs] = text_indent
|
873
845
|
end
|
874
846
|
if (bottom_gutter = @bottom_gutters[-1][node])
|
@@ -915,7 +887,7 @@ module Asciidoctor
|
|
915
887
|
label_width = label_min_width || (icon_size * 1.5)
|
916
888
|
elsif (icon_path = has_icon || !(icon_path = (@theme[%(admonition_icon_#{type})] || {})[:image]) ?
|
917
889
|
(get_icon_image_path node, type) :
|
918
|
-
(ThemeLoader.resolve_theme_asset (apply_subs_discretely doc, icon_path, subs: [:attributes]), @themesdir)) &&
|
890
|
+
(ThemeLoader.resolve_theme_asset (apply_subs_discretely doc, icon_path, subs: [:attributes], imagesdir: @themesdir), @themesdir)) &&
|
919
891
|
(::File.readable? icon_path)
|
920
892
|
icons = true
|
921
893
|
# TODO: introduce @theme.admonition_image_width? or use size key from admonition_icon_<name>?
|
@@ -1073,7 +1045,7 @@ module Asciidoctor
|
|
1073
1045
|
else
|
1074
1046
|
highlighter = nil
|
1075
1047
|
end
|
1076
|
-
|
1048
|
+
saved_subs = (subs = node.subs).dup
|
1077
1049
|
callouts_enabled = subs.include? :callouts
|
1078
1050
|
highlight_idx = subs.index :highlight
|
1079
1051
|
# NOTE: scratch? here only applies if listing block is nested inside another block
|
@@ -1083,16 +1055,33 @@ module Asciidoctor
|
|
1083
1055
|
# switch the :highlight sub back to :specialcharacters
|
1084
1056
|
subs[highlight_idx] = :specialcharacters
|
1085
1057
|
else
|
1086
|
-
|
1058
|
+
saved_subs = nil
|
1087
1059
|
end
|
1088
1060
|
source_string = guard_indentation node.content
|
1089
1061
|
elsif highlight_idx
|
1090
1062
|
# NOTE: the source highlighter logic below handles the highlight and callouts subs
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1063
|
+
if (subs - [:highlight, :callouts]).empty?
|
1064
|
+
subs.clear
|
1065
|
+
# NOTE: indentation guards will be added by the source highlighter logic
|
1066
|
+
source_string = expand_tabs node.content
|
1067
|
+
else
|
1068
|
+
if callouts_enabled
|
1069
|
+
saved_lines = node.lines.dup
|
1070
|
+
subs.delete :callouts
|
1071
|
+
prev_subs = subs.dup
|
1072
|
+
subs.clear
|
1073
|
+
source_string, conum_mapping = extract_conums node.content
|
1074
|
+
node.lines.replace (source_string.split LF)
|
1075
|
+
subs.replace prev_subs
|
1076
|
+
callouts_enabled = false
|
1077
|
+
end
|
1078
|
+
subs[highlight_idx] = :specialcharacters
|
1079
|
+
# NOTE: indentation guards will be added by the source highlighter logic
|
1080
|
+
source_string = expand_tabs unescape_xml (sanitize node.content, compact: false)
|
1081
|
+
node.lines.replace saved_lines if saved_lines
|
1082
|
+
end
|
1094
1083
|
else
|
1095
|
-
highlighter =
|
1084
|
+
highlighter = saved_subs = nil
|
1096
1085
|
source_string = guard_indentation node.content
|
1097
1086
|
end
|
1098
1087
|
else
|
@@ -1184,7 +1173,7 @@ module Asciidoctor
|
|
1184
1173
|
# NOTE: only format if we detect a need (callouts or inline formatting)
|
1185
1174
|
source_chunks = (XMLMarkupRx.match? source_string) ? (text_formatter.format source_string) : [text: source_string]
|
1186
1175
|
end
|
1187
|
-
node.subs.replace
|
1176
|
+
node.subs.replace saved_subs if saved_subs
|
1188
1177
|
adjusted_font_size = ((node.option? 'autofit') || (node.document.attr? 'autofit-option')) ? (compute_autofit_font_size source_chunks, :code) : nil
|
1189
1178
|
end
|
1190
1179
|
|
@@ -1308,7 +1297,7 @@ module Asciidoctor
|
|
1308
1297
|
content = guard_indentation node.content
|
1309
1298
|
ink_prose content,
|
1310
1299
|
normalize: false,
|
1311
|
-
align: :left,
|
1300
|
+
align: (resolve_text_align_from_role node.roles) || :left,
|
1312
1301
|
hyphenate: true,
|
1313
1302
|
margin_bottom: 0,
|
1314
1303
|
bottom_gutter: (attribution ? nil : @bottom_gutters[-1][node])
|
@@ -1462,7 +1451,8 @@ module Asciidoctor
|
|
1462
1451
|
end
|
1463
1452
|
max_term_width += (term_padding[1] + term_padding[3])
|
1464
1453
|
term_column_width = [max_term_width, bounds.width * 0.5].min
|
1465
|
-
table table_data, position: :left,
|
1454
|
+
table table_data, position: :left, column_widths: [term_column_width] do
|
1455
|
+
cells.style border_width: 0
|
1466
1456
|
@pdf.ink_table_caption node if node.title?
|
1467
1457
|
end
|
1468
1458
|
theme_margin :prose, :bottom, (next_enclosed_block actual_node) #unless actual_node.nested?
|
@@ -1631,6 +1621,9 @@ module Asciidoctor
|
|
1631
1621
|
marker = node.parent.style == 'decimal' && index.abs < 10 ? %(#{index < 0 ? '-' : ''}0#{index.abs}.) : %(#{index}.)
|
1632
1622
|
dir = (node.parent.option? 'reversed') ? :pred : :next
|
1633
1623
|
@list_numerals << (index.public_send dir)
|
1624
|
+
[:font_color, :font_family, :font_size, :font_style, :line_height].each do |prop|
|
1625
|
+
marker_style[prop] = @theme[%(olist_marker_#{prop})] || marker_style[prop]
|
1626
|
+
end
|
1634
1627
|
end
|
1635
1628
|
end
|
1636
1629
|
else # :ulist
|
@@ -1645,7 +1638,7 @@ module Asciidoctor
|
|
1645
1638
|
else
|
1646
1639
|
marker = @theme[%(ulist_marker_#{marker_type}_content)] || Bullets[marker_type]
|
1647
1640
|
end
|
1648
|
-
[:font_color, :font_family, :font_size, :line_height].each do |prop|
|
1641
|
+
[:font_color, :font_family, :font_size, :font_style, :line_height].each do |prop|
|
1649
1642
|
marker_style[prop] = @theme[%(ulist_marker_#{marker_type}_#{prop})] || @theme[%(ulist_marker_#{prop})] || marker_style[prop]
|
1650
1643
|
end if marker
|
1651
1644
|
end
|
@@ -1656,8 +1649,9 @@ module Asciidoctor
|
|
1656
1649
|
log :info, 'deprecated fa icon set found in theme; use fas, far, or fab instead'
|
1657
1650
|
marker_style[:font_family] = FontAwesomeIconSets.find {|candidate| (icon_font_data candidate).yaml[candidate].value? marker } || 'fas'
|
1658
1651
|
end
|
1652
|
+
marker_style[:font_style] &&= marker_style[:font_style].to_sym
|
1659
1653
|
marker_gap = rendered_width_of_char 'x'
|
1660
|
-
font marker_style[:font_family], marker_style[:font_size] do
|
1654
|
+
font marker_style[:font_family], size: marker_style[:font_size], style: marker_style[:font_style] do
|
1661
1655
|
marker_width = rendered_width_of_string marker
|
1662
1656
|
# NOTE: compensate if character_spacing is not applied to first character
|
1663
1657
|
# see https://github.com/prawnpdf/prawn/commit/c61c5d48841910aa11b9e3d6f0e01b68ce435329
|
@@ -1676,6 +1670,7 @@ module Asciidoctor
|
|
1676
1670
|
color: marker_style[:font_color],
|
1677
1671
|
inline_format: false,
|
1678
1672
|
line_height: marker_style[:line_height],
|
1673
|
+
style: marker_style[:font_style],
|
1679
1674
|
margin: 0,
|
1680
1675
|
normalize: false,
|
1681
1676
|
single_line: true
|
@@ -1703,7 +1698,7 @@ module Asciidoctor
|
|
1703
1698
|
alignment = float_to.to_sym
|
1704
1699
|
elsif (alignment = node.attr 'align')
|
1705
1700
|
alignment = (BlockAlignmentNames.include? alignment) ? alignment.to_sym : :left
|
1706
|
-
elsif !(alignment = node.roles.reverse.find {|
|
1701
|
+
elsif !(alignment = node.roles.reverse.find {|role| BlockAlignmentNames.include? role }&.to_sym)
|
1707
1702
|
alignment = @theme.image_align&.to_sym || :left
|
1708
1703
|
end
|
1709
1704
|
end
|
@@ -1937,14 +1932,16 @@ module Asciidoctor
|
|
1937
1932
|
page_layout = nil
|
1938
1933
|
end
|
1939
1934
|
|
1940
|
-
if at_page_top?
|
1935
|
+
if at_page_top? && !(node.option? 'always')
|
1941
1936
|
if page_layout && page_layout != page.layout && page.empty?
|
1942
1937
|
delete_current_page
|
1943
|
-
advance_page layout: page_layout
|
1938
|
+
advance_page layout: page_layout, margin: @page_margin[page_layout][page_side nil, @folio_placement[:inverted]]
|
1944
1939
|
end
|
1945
1940
|
elsif page_layout
|
1946
|
-
|
1941
|
+
bounds.current_column = bounds.last_column if ColumnBox === bounds && !(node.has_role? 'column')
|
1942
|
+
advance_page layout: page_layout, margin: @page_margin[page_layout][page_side nil, @folio_placement[:inverted]]
|
1947
1943
|
else
|
1944
|
+
bounds.current_column = bounds.last_column if ColumnBox === bounds && !(node.has_role? 'column')
|
1948
1945
|
advance_page
|
1949
1946
|
end
|
1950
1947
|
end
|
@@ -2217,7 +2214,7 @@ module Asciidoctor
|
|
2217
2214
|
|
2218
2215
|
if node.option? 'autowidth'
|
2219
2216
|
table_width = (node.attr? 'width') ? bounds.width * ((node.attr 'tablepcwidth') / 100.0) :
|
2220
|
-
(((node.has_role? 'stretch')
|
2217
|
+
(((node.has_role? 'stretch')) ? bounds.width : nil)
|
2221
2218
|
column_widths = []
|
2222
2219
|
else
|
2223
2220
|
table_width = bounds.width * ((node.attr 'tablepcwidth') / 100.0)
|
@@ -2239,10 +2236,10 @@ module Asciidoctor
|
|
2239
2236
|
# NOTE: position is handled by this method
|
2240
2237
|
position: :left,
|
2241
2238
|
# NOTE: the border color, style, and width of the outer frame is set in the table callback block
|
2242
|
-
cell_style: { border_color: grid_color.values, border_lines: grid_style.values, border_width: grid_width.values },
|
2243
2239
|
width: table_width,
|
2244
2240
|
column_widths: column_widths,
|
2245
2241
|
}
|
2242
|
+
cell_style = { border_color: grid_color.values, border_lines: grid_style.values, border_width: grid_width.values }
|
2246
2243
|
|
2247
2244
|
# QUESTION: should we support nth; should we support sequence of roles?
|
2248
2245
|
case node.attr 'stripes', nil, 'table-stripes'
|
@@ -2258,6 +2255,8 @@ module Asciidoctor
|
|
2258
2255
|
|
2259
2256
|
left_padding = right_padding = nil
|
2260
2257
|
table table_data, table_settings do
|
2258
|
+
# NOTE: cell_style must be applied manually to be compatible with both prawn-table 0.2.2 and prawn-table 0.2.3
|
2259
|
+
cells.style cell_style
|
2261
2260
|
@column_widths = column_widths unless column_widths.empty?
|
2262
2261
|
# NOTE: call width to capture resolved table width
|
2263
2262
|
table_width = width
|
@@ -2381,6 +2380,9 @@ module Asciidoctor
|
|
2381
2380
|
node.content
|
2382
2381
|
elsif node.content_model != :compound && (string = node.content)
|
2383
2382
|
prose_opts = opts.merge hyphenate: true, margin_bottom: 0
|
2383
|
+
if (text_align = resolve_text_align_from_role node.roles)
|
2384
|
+
prose_opts[:align] = text_align
|
2385
|
+
end
|
2384
2386
|
if (bottom_gutter = @bottom_gutters[-1][node])
|
2385
2387
|
prose_opts[:bottom_gutter] = bottom_gutter
|
2386
2388
|
end
|
@@ -2429,7 +2431,7 @@ module Asciidoctor
|
|
2429
2431
|
# QUESTION: should we insert breakable chars into URI when building fragment instead?
|
2430
2432
|
%(#{anchor}<a href="#{target}"#{attrs.join}>#{breakable_uri text}</a>)
|
2431
2433
|
# NOTE: @media may not be initialized if method is called before convert phase
|
2432
|
-
elsif (doc.attr? 'show-link-uri') ||
|
2434
|
+
elsif (doc.attr? 'show-link-uri') || (@media != 'screen' && (doc.attr_unspecified? 'show-link-uri'))
|
2433
2435
|
# QUESTION: should we insert breakable chars into URI when building fragment instead?
|
2434
2436
|
# TODO: allow style of printed link to be controlled by theme
|
2435
2437
|
%(#{anchor}<a href="#{target}"#{attrs.join}>#{text}</a> [<font size="0.85em">#{breakable_uri bare_target}</font>])
|
@@ -2496,9 +2498,9 @@ module Asciidoctor
|
|
2496
2498
|
else
|
2497
2499
|
label = index
|
2498
2500
|
end
|
2499
|
-
%(
|
2501
|
+
%(<sup class="wj">#{anchor}[<a anchor="_footnotedef_#{index}">#{label}</a>]</sup>)
|
2500
2502
|
elsif node.type == :xref
|
2501
|
-
%(<sup><font color="#{theme.role_unresolved_font_color}">[#{node.text}]</font></sup>)
|
2503
|
+
%(<sup class="wj"><font color="#{theme.role_unresolved_font_color}">[#{node.text}]</font></sup>)
|
2502
2504
|
else
|
2503
2505
|
log :warn, %(unknown footnote type: #{node.type.inspect})
|
2504
2506
|
nil
|
@@ -2793,6 +2795,11 @@ module Asciidoctor
|
|
2793
2795
|
if (imagesdir = opts[:imagesdir])
|
2794
2796
|
imagesdir_to_restore = doc.attr 'imagesdir'
|
2795
2797
|
doc.set_attr 'imagesdir', imagesdir
|
2798
|
+
remove_docimagesdir = doc.set_attr 'docimagesdir', (::File.absolute_path imagesdir_to_restore.to_s, (doc.attr 'docdir', '')), false
|
2799
|
+
end
|
2800
|
+
if (page_layout = opts[:page_layout])
|
2801
|
+
page_layout_to_restore = doc.attr 'page-layout'
|
2802
|
+
doc.set_attr 'page-layout', page.layout.to_s
|
2796
2803
|
end
|
2797
2804
|
# FIXME: get sub_attributes to handle drop-line w/o a warning
|
2798
2805
|
doc.set_attr 'attribute-missing', 'skip' unless (attribute_missing = doc.attr 'attribute-missing') == 'skip'
|
@@ -2801,20 +2808,26 @@ module Asciidoctor
|
|
2801
2808
|
value = (value.split LF).delete_if {|line| SimpleAttributeRefRx.match? line }.join LF if opts[:drop_lines_with_unresolved_attributes] && (value.include? '{')
|
2802
2809
|
value = value.gsub '\{', '{' if escaped_attr_ref
|
2803
2810
|
doc.set_attr 'attribute-missing', attribute_missing unless attribute_missing == 'skip'
|
2804
|
-
|
2811
|
+
page_layout_to_restore ? (doc.set_attr 'page-layout', page_layout_to_restore) : (doc.remove_attr 'page-layout') if page_layout
|
2812
|
+
if imagesdir
|
2813
|
+
imagesdir_to_restore ? (doc.set_attr 'imagesdir', imagesdir_to_restore) : (doc.remove_attr 'imagesdir')
|
2814
|
+
doc.remove_attr 'docimagesdir' if remove_docimagesdir
|
2815
|
+
end
|
2805
2816
|
value
|
2806
2817
|
end
|
2807
2818
|
|
2808
2819
|
# Position the cursor for where to ink the specified section title or discrete heading node.
|
2809
2820
|
#
|
2810
|
-
# This method computes whether there
|
2811
|
-
# from being orphaned. If there
|
2821
|
+
# This method computes whether there's enough room on the page to prevent the specified node
|
2822
|
+
# from being orphaned. If there's not enough room, the method will advance the cursor to
|
2812
2823
|
# the next page. This method is not called if the cursor is already at the top of the page or
|
2813
2824
|
# whether this node has no node that follows it in document order.
|
2814
2825
|
def arrange_heading node, title, opts
|
2815
|
-
if node.option? 'breakable'
|
2826
|
+
if (min_height_after = @theme.heading_min_height_after) == 'auto' || (node.option? 'breakable')
|
2816
2827
|
orphaned = nil
|
2828
|
+
doc = node.document
|
2817
2829
|
dry_run single_page: true do
|
2830
|
+
push_scratch doc
|
2818
2831
|
start_page = page
|
2819
2832
|
theme_font :heading, level: opts[:level] do
|
2820
2833
|
if opts[:part]
|
@@ -2829,19 +2842,18 @@ module Asciidoctor
|
|
2829
2842
|
page.tare_content_stream
|
2830
2843
|
orphaned = stop_if_first_page_empty { node.context == :section ? (traverse node) : (convert node.next_sibling) }
|
2831
2844
|
end
|
2845
|
+
ensure
|
2846
|
+
pop_scratch doc
|
2832
2847
|
end
|
2833
2848
|
advance_page if orphaned
|
2834
2849
|
else
|
2835
2850
|
theme_font :heading, level: (hlevel = opts[:level]) do
|
2836
2851
|
h_padding_t, h_padding_r, h_padding_b, h_padding_l = expand_padding_value @theme[%(heading_h#{hlevel}_padding)]
|
2837
2852
|
h_fits = indent h_padding_l, h_padding_r do
|
2838
|
-
|
2839
|
-
heading_h = (height_of_typeset_text title) +
|
2853
|
+
heading_h = (height_of_typeset_text title, inline_format: true, text_transform: @text_transform) +
|
2840
2854
|
(@theme[%(heading_h#{hlevel}_margin_top)] || @theme.heading_margin_top) +
|
2841
2855
|
(@theme[%(heading_h#{hlevel}_margin_bottom)] || @theme.heading_margin_bottom) + h_padding_t + h_padding_b
|
2842
|
-
|
2843
|
-
heading_h += min_height_after
|
2844
|
-
end
|
2856
|
+
heading_h += min_height_after if min_height_after && (node.context == :section ? node.blocks? : !node.last_child?)
|
2845
2857
|
cursor >= heading_h
|
2846
2858
|
end
|
2847
2859
|
advance_page unless h_fits
|
@@ -3010,8 +3022,16 @@ module Asciidoctor
|
|
3010
3022
|
end
|
3011
3023
|
|
3012
3024
|
def height_of_typeset_text string, opts = {}
|
3025
|
+
if (transform = opts[:text_transform])
|
3026
|
+
string = transform_text string, transform
|
3027
|
+
end
|
3028
|
+
if (inline_format = opts[:inline_format]) && (InlineFormatSniffRx.match? string)
|
3029
|
+
fragments = parse_text string, inline_format: inline_format
|
3030
|
+
else
|
3031
|
+
fragments = [{ text: string }]
|
3032
|
+
end
|
3013
3033
|
line_metrics = (calc_line_metrics opts[:line_height] || @base_line_height)
|
3014
|
-
(
|
3034
|
+
(height_of_formatted fragments, leading: line_metrics.leading, final_gap: line_metrics.final_gap) + line_metrics.padding_top + (opts[:single_line] ? 0 : line_metrics.padding_bottom)
|
3015
3035
|
end
|
3016
3036
|
|
3017
3037
|
# Render the caption in the current document. If the dry_run option is true, return the height.
|
@@ -3103,7 +3123,7 @@ module Asciidoctor
|
|
3103
3123
|
opts = opts.merge inherited
|
3104
3124
|
end
|
3105
3125
|
unless scratch? || !(bg_color = @theme[%(#{category_caption}_background_color)] || @theme.caption_background_color)
|
3106
|
-
caption_height = height_of_typeset_text string
|
3126
|
+
caption_height = height_of_typeset_text string, inline_format: true, text_transform: @text_transform
|
3107
3127
|
fill_at = [bounds.left, cursor]
|
3108
3128
|
fill_at[1] -= (margin[:top] || 0) unless at_page_top?
|
3109
3129
|
float { bounding_box(fill_at, width: container_width, height: caption_height) { fill_bounds bg_color } }
|
@@ -3143,7 +3163,7 @@ module Asciidoctor
|
|
3143
3163
|
open_graphics_state if face == :front
|
3144
3164
|
return
|
3145
3165
|
elsif image_path == '~'
|
3146
|
-
@
|
3166
|
+
@page_margin[:cover] = @page_margin[page.layout][:recto] if @media == 'prepress'
|
3147
3167
|
return
|
3148
3168
|
end
|
3149
3169
|
|
@@ -3164,9 +3184,9 @@ module Asciidoctor
|
|
3164
3184
|
def ink_footnotes node
|
3165
3185
|
return if (fns = (doc = node.document).footnotes - @rendered_footnotes).empty?
|
3166
3186
|
theme_margin :block, :bottom if node.context == :document || node == node.document.last_child
|
3167
|
-
theme_margin :footnotes, :top
|
3187
|
+
theme_margin :footnotes, :top unless (valign_bottom = @theme.footnotes_margin_top == 'auto')
|
3168
3188
|
with_dry_run do |extent|
|
3169
|
-
if (single_page_height = extent&.single_page_height) && (delta = cursor - single_page_height - 0.0001) > 0
|
3189
|
+
if valign_bottom && (single_page_height = extent&.single_page_height) && (delta = cursor - single_page_height - 0.0001) > 0
|
3170
3190
|
move_down delta
|
3171
3191
|
end
|
3172
3192
|
theme_font :footnotes do
|
@@ -3274,7 +3294,7 @@ module Asciidoctor
|
|
3274
3294
|
|
3275
3295
|
def allocate_running_content_layout doc, page, periphery, cache
|
3276
3296
|
cache[layout = page.layout] ||= begin
|
3277
|
-
page_margin_recto = @
|
3297
|
+
page_margin_recto = @page_margin[layout][:recto]
|
3278
3298
|
trim_margin_recto = @theme[%(#{periphery}_recto_margin)] || @theme[%(#{periphery}_margin)] || [0, 'inherit', 0, 'inherit']
|
3279
3299
|
trim_margin_recto = (expand_margin_value trim_margin_recto).map.with_index {|v, i| i.odd? && v == 'inherit' ? page_margin_recto[i] : v.to_f }
|
3280
3300
|
trim_content_margin_recto = @theme[%(#{periphery}_recto_content_margin)] || @theme[%(#{periphery}_content_margin)] || [0, 'inherit', 0, 'inherit']
|
@@ -3284,7 +3304,7 @@ module Asciidoctor
|
|
3284
3304
|
else
|
3285
3305
|
trim_padding_recto = trim_content_margin_recto
|
3286
3306
|
end
|
3287
|
-
page_margin_verso = @
|
3307
|
+
page_margin_verso = @page_margin[layout][:verso]
|
3288
3308
|
trim_margin_verso = @theme[%(#{periphery}_verso_margin)] || @theme[%(#{periphery}_margin)] || [0, 'inherit', 0, 'inherit']
|
3289
3309
|
trim_margin_verso = (expand_margin_value trim_margin_verso).map.with_index {|v, i| i.odd? && v == 'inherit' ? page_margin_verso[i] : v.to_f }
|
3290
3310
|
trim_content_margin_verso = @theme[%(#{periphery}_verso_content_margin)] || @theme[%(#{periphery}_content_margin)] || [0, 'inherit', 0, 'inherit']
|
@@ -3679,7 +3699,7 @@ module Asciidoctor
|
|
3679
3699
|
logo_image_attrs = (AttributeList.new $2).parse %w(alt width height)
|
3680
3700
|
if logo_image_from_theme
|
3681
3701
|
relative_to_imagesdir = false
|
3682
|
-
logo_image_path = apply_subs_discretely doc, $1, subs: [:attributes]
|
3702
|
+
logo_image_path = apply_subs_discretely doc, $1, subs: [:attributes], imagesdir: @themesdir
|
3683
3703
|
logo_image_path = ThemeLoader.resolve_theme_asset logo_image_path, @themesdir unless doc.is_uri? logo_image_path
|
3684
3704
|
else
|
3685
3705
|
relative_to_imagesdir = true
|
@@ -3689,7 +3709,7 @@ module Asciidoctor
|
|
3689
3709
|
logo_image_attrs = {}
|
3690
3710
|
relative_to_imagesdir = false
|
3691
3711
|
if logo_image_from_theme
|
3692
|
-
logo_image_path = apply_subs_discretely doc, logo_image_path, subs: [:attributes]
|
3712
|
+
logo_image_path = apply_subs_discretely doc, logo_image_path, subs: [:attributes], imagesdir: @themesdir
|
3693
3713
|
logo_image_path = ThemeLoader.resolve_theme_asset logo_image_path, @themesdir unless doc.is_uri? logo_image_path
|
3694
3714
|
end
|
3695
3715
|
end
|
@@ -3775,12 +3795,12 @@ module Asciidoctor
|
|
3775
3795
|
end
|
3776
3796
|
end
|
3777
3797
|
|
3778
|
-
def allocate_toc doc, toc_num_levels, toc_start_cursor,
|
3798
|
+
def allocate_toc doc, toc_num_levels, toc_start_cursor, break_after_toc
|
3779
3799
|
toc_start_page_number = page_number
|
3780
3800
|
to_page = nil
|
3781
3801
|
extent = dry_run onto: self do
|
3782
3802
|
to_page = (ink_toc doc, toc_num_levels, toc_start_page_number, toc_start_cursor).end
|
3783
|
-
theme_margin :block, :bottom unless
|
3803
|
+
theme_margin :block, :bottom unless break_after_toc
|
3784
3804
|
end
|
3785
3805
|
# NOTE: patch for custom converters that allocate extra TOC pages without actually creating them
|
3786
3806
|
if to_page > extent.to.page
|
@@ -3788,7 +3808,7 @@ module Asciidoctor
|
|
3788
3808
|
extent.to.cursor = bounds.height
|
3789
3809
|
end
|
3790
3810
|
# NOTE: reserve pages for the toc; leaves cursor on page after last page in toc
|
3791
|
-
if
|
3811
|
+
if break_after_toc
|
3792
3812
|
extent.each_page { start_new_page }
|
3793
3813
|
else
|
3794
3814
|
extent.each_page {|first_page| start_new_page unless first_page }
|
@@ -4059,18 +4079,14 @@ module Asciidoctor
|
|
4059
4079
|
return []
|
4060
4080
|
elsif (image_path.include? ':') && image_path =~ ImageAttributeValueRx
|
4061
4081
|
image_attrs = (AttributeList.new $2).parse %w(alt width)
|
4062
|
-
|
4063
|
-
|
4064
|
-
|
4065
|
-
|
4066
|
-
|
4067
|
-
|
4068
|
-
|
4069
|
-
elsif from_theme
|
4070
|
-
image_path = apply_subs_discretely doc, image_path, subs: [:attributes]
|
4071
|
-
image_relative_to = @themesdir
|
4082
|
+
image_path = $1
|
4083
|
+
image_relative_to = true
|
4084
|
+
end
|
4085
|
+
if from_theme
|
4086
|
+
image_path = apply_subs_discretely doc, image_path, subs: [:attributes], imagesdir: (image_relative_to = @themesdir), page_layout: page.layout.to_s
|
4087
|
+
elsif image_path.include? '{page-layout}'
|
4088
|
+
image_path = image_path.sub '{page-layout}', page.layout.to_s
|
4072
4089
|
end
|
4073
|
-
|
4074
4090
|
image_path, image_format = ::Asciidoctor::Image.target_and_format image_path, image_attrs
|
4075
4091
|
image_path = resolve_image_path doc, image_path, image_format, image_relative_to
|
4076
4092
|
|
@@ -4284,9 +4300,30 @@ module Asciidoctor
|
|
4284
4300
|
end
|
4285
4301
|
end
|
4286
4302
|
|
4303
|
+
def resolve_page_margin value
|
4304
|
+
return if value.nil_or_empty?
|
4305
|
+
case value
|
4306
|
+
when ::Array
|
4307
|
+
value = value.slice 0, 4 if value.length > 4
|
4308
|
+
value.map {|v| ::Numeric === v ? v : (str_to_pt v.to_s) }
|
4309
|
+
when ::Numeric
|
4310
|
+
[value]
|
4311
|
+
when ::String
|
4312
|
+
if (value.start_with? '[') && (value.end_with? ']')
|
4313
|
+
return if (value = (value.slice 1, value.length - 2).rstrip).empty?
|
4314
|
+
if (value = value.split ',', -1).length > 4
|
4315
|
+
value = value.slice 0, 4
|
4316
|
+
end
|
4317
|
+
value.map {|v| str_to_pt v.rstrip }
|
4318
|
+
else
|
4319
|
+
[(str_to_pt value)]
|
4320
|
+
end
|
4321
|
+
end
|
4322
|
+
end
|
4323
|
+
|
4287
4324
|
def resolve_text_align_from_role roles, query_theme: false, remove_predefined: false
|
4288
|
-
if (align_role = roles.reverse.find {|
|
4289
|
-
roles.replace roles - TextAlignmentRoles if remove_predefined
|
4325
|
+
if (align_role = roles.reverse.find {|role| TextAlignmentRoles[role] })
|
4326
|
+
roles.replace roles - TextAlignmentRoles.keys if remove_predefined
|
4290
4327
|
(align_role.slice 5, align_role.length).to_sym
|
4291
4328
|
elsif query_theme
|
4292
4329
|
roles.reverse.each do |role|
|
@@ -4336,17 +4373,17 @@ module Asciidoctor
|
|
4336
4373
|
elsif @ppbook && page_number > 0 && recto_page?
|
4337
4374
|
start_new_page
|
4338
4375
|
end
|
4339
|
-
side = page_side (recycle ? nil : page_number + 1), @folio_placement[:inverted]
|
4340
|
-
prev_bg_image = @page_bg_image[side]
|
4341
|
-
prev_bg_color = @page_bg_color
|
4342
4376
|
if (bg_image = resolve_background_image doc, @theme, 'title-page-background-image')
|
4343
|
-
|
4377
|
+
side = page_side (recycle ? nil : page_number + 1), @folio_placement[:inverted]
|
4378
|
+
prev_bg_image = get_page_bg_image doc, @theme, (layout = page.layout), side
|
4379
|
+
@page_bg_image[layout][side] = bg_image[0] && bg_image
|
4344
4380
|
end
|
4345
4381
|
if (bg_color = resolve_theme_color :title_page_background_color)
|
4382
|
+
prev_bg_color = @page_bg_color
|
4346
4383
|
@page_bg_color = bg_color
|
4347
4384
|
end
|
4348
|
-
recycle ? float { init_page self } : start_new_page
|
4349
|
-
@page_bg_image[side] = prev_bg_image if bg_image
|
4385
|
+
recycle ? float { init_page doc, self } : start_new_page
|
4386
|
+
@page_bg_image[layout][side] = prev_bg_image if bg_image
|
4350
4387
|
@page_bg_color = prev_bg_color if bg_color
|
4351
4388
|
true
|
4352
4389
|
end
|
@@ -4433,7 +4470,12 @@ module Asciidoctor
|
|
4433
4470
|
if opts.key? :level
|
4434
4471
|
hlevel_category = %(#{category}_h#{opts[:level]})
|
4435
4472
|
family = @theme[%(#{hlevel_category}_font_family)] || @theme[%(#{category}_font_family)] || @theme.base_font_family || font_family
|
4436
|
-
size =
|
4473
|
+
if (size = @theme[%(#{hlevel_category}_font_size)] || @theme[%(#{category}_font_size)])
|
4474
|
+
scale = @font_scale unless ::String === size
|
4475
|
+
else
|
4476
|
+
scale = @font_scale
|
4477
|
+
size = @root_font_size
|
4478
|
+
end
|
4437
4479
|
style = @theme[%(#{hlevel_category}_font_style)] || @theme[%(#{category}_font_style)]
|
4438
4480
|
color = @theme[%(#{hlevel_category}_font_color)] || @theme[%(#{category}_font_color)]
|
4439
4481
|
kerning = resolve_font_kerning @theme[%(#{hlevel_category}_font_kerning)] || @theme[%(#{category}_font_kerning)]
|
@@ -4443,7 +4485,11 @@ module Asciidoctor
|
|
4443
4485
|
else
|
4444
4486
|
inherited_font = font_info
|
4445
4487
|
family = @theme[%(#{category}_font_family)] || inherited_font[:family]
|
4446
|
-
|
4488
|
+
if (size = @theme[%(#{category}_font_size)])
|
4489
|
+
scale = @font_scale unless ::String === size
|
4490
|
+
else
|
4491
|
+
size = inherited_font[:size]
|
4492
|
+
end
|
4447
4493
|
style = @theme[%(#{category}_font_style)] || inherited_font[:style]
|
4448
4494
|
color = @theme[%(#{category}_font_color)]
|
4449
4495
|
kerning = resolve_font_kerning @theme[%(#{category}_font_kerning)]
|
@@ -4459,6 +4505,7 @@ module Asciidoctor
|
|
4459
4505
|
|
4460
4506
|
result = nil
|
4461
4507
|
font family, size: size, style: style&.to_sym do
|
4508
|
+
@font_size *= scale if scale
|
4462
4509
|
result = yield
|
4463
4510
|
ensure
|
4464
4511
|
@font_color = prev_color if color
|
@@ -4518,6 +4565,7 @@ module Asciidoctor
|
|
4518
4565
|
# QUESTION: combine with typeset_text?
|
4519
4566
|
def typeset_formatted_text fragments, line_metrics, opts = {}
|
4520
4567
|
opts = { leading: line_metrics.leading, initial_gap: line_metrics.padding_top, final_gap: line_metrics.final_gap }.merge opts
|
4568
|
+
fragments = consolidate_fragments fragments if opts.delete :consolidate
|
4521
4569
|
if (hanging_indent = (opts.delete :hanging_indent) || 0) > 0
|
4522
4570
|
indent hanging_indent do
|
4523
4571
|
formatted_text fragments, (opts.merge indent_paragraphs: -hanging_indent)
|
@@ -4727,6 +4775,20 @@ module Asciidoctor
|
|
4727
4775
|
end
|
4728
4776
|
end
|
4729
4777
|
|
4778
|
+
def consolidate_fragments fragments
|
4779
|
+
return fragments unless fragments.size > 1
|
4780
|
+
accum = []
|
4781
|
+
prev_fragment = nil
|
4782
|
+
fragments.each do |fragment|
|
4783
|
+
if prev_fragment && fragment == (prev_fragment.merge text: (fragment_text = fragment[:text]))
|
4784
|
+
prev_fragment[:text] += fragment_text
|
4785
|
+
else
|
4786
|
+
accum << (prev_fragment = fragment)
|
4787
|
+
end
|
4788
|
+
end
|
4789
|
+
accum
|
4790
|
+
end
|
4791
|
+
|
4730
4792
|
def conum_glyph number
|
4731
4793
|
@conum_glyphs[number - 1]
|
4732
4794
|
end
|
@@ -4795,6 +4857,23 @@ module Asciidoctor
|
|
4795
4857
|
(code.start_with? '\u') ? ([((code.slice 2, code.length).to_i 16)].pack 'U1') : code
|
4796
4858
|
end
|
4797
4859
|
|
4860
|
+
def get_page_bg_image doc, theme_, layout, side
|
4861
|
+
(@page_bg_image[layout] ||= begin
|
4862
|
+
if (bg_image = resolve_background_image doc, theme_, 'page-background-image')&.first
|
4863
|
+
val = { verso: bg_image, recto: bg_image }
|
4864
|
+
else
|
4865
|
+
val = { verso: nil, recto: nil }
|
4866
|
+
end
|
4867
|
+
if (bg_image = resolve_background_image doc, theme_, 'page-background-image-verso')
|
4868
|
+
val[:verso] = bg_image[0] && bg_image
|
4869
|
+
end
|
4870
|
+
if (bg_image = resolve_background_image doc, theme_, 'page-background-image-recto')
|
4871
|
+
val[:recto] = bg_image[0] && bg_image
|
4872
|
+
end
|
4873
|
+
val
|
4874
|
+
end)[side]
|
4875
|
+
end
|
4876
|
+
|
4798
4877
|
def get_icon_image_path node, type, resolve = true
|
4799
4878
|
doc = node.document
|
4800
4879
|
doc.remove_attr 'data-uri' if (data_uri_enabled = doc.attr? 'data-uri')
|
@@ -4818,18 +4897,17 @@ module Asciidoctor
|
|
4818
4897
|
@float_box = { page: page_number, top: box_t, right: box_r, bottom: box_b, left: box_l, width: box_w, height: box_h, gap: gap }
|
4819
4898
|
end
|
4820
4899
|
|
4821
|
-
# NOTE: init_page is called within a float context; this will suppress prawn-svg messing with the cursor
|
4822
4900
|
# NOTE: init_page is not called for imported pages, cover pages, image pages, and pages in the scratch document
|
4823
|
-
def init_page
|
4901
|
+
def init_page doc, _self
|
4824
4902
|
next_page_side = page_side nil, @folio_placement[:inverted]
|
4825
|
-
if @media == 'prepress' && (next_page_margin =
|
4903
|
+
if @media == 'prepress' && (next_page_margin = page_number == 1 ? @page_margin[:cover] : @page_margin[page.layout][next_page_side]) != page_margin
|
4826
4904
|
set_page_margin next_page_margin
|
4827
4905
|
end
|
4828
4906
|
unless @page_bg_color == 'FFFFFF'
|
4829
4907
|
fill_absolute_bounds @page_bg_color
|
4830
4908
|
tare = true
|
4831
4909
|
end
|
4832
|
-
if (bg_image_path, bg_image_opts = @
|
4910
|
+
if (bg_image_path, bg_image_opts = get_page_bg_image doc, @theme, (layout = page.layout), next_page_side)
|
4833
4911
|
begin
|
4834
4912
|
if bg_image_opts[:format] == 'pdf'
|
4835
4913
|
# NOTE: pages that use PDF for the background do not support a background color or running content
|
@@ -4840,9 +4918,10 @@ module Asciidoctor
|
|
4840
4918
|
end
|
4841
4919
|
tare = true
|
4842
4920
|
rescue
|
4843
|
-
facing_page_side = (PageSides -
|
4844
|
-
|
4845
|
-
|
4921
|
+
facing_page_side = PageSides[(PageSides.index next_page_side) - 1]
|
4922
|
+
bg_image_by_side = @page_bg_image[layout]
|
4923
|
+
bg_image_by_side[facing_page_side] = nil if bg_image_by_side[facing_page_side] == bg_image_by_side[next_page_side]
|
4924
|
+
bg_image_by_side[next_page_side] = nil
|
4846
4925
|
log :warn, %(could not embed page background image: #{bg_image_path}; #{$!.message})
|
4847
4926
|
end
|
4848
4927
|
end
|
@@ -5013,7 +5092,9 @@ module Asciidoctor
|
|
5013
5092
|
end
|
5014
5093
|
|
5015
5094
|
def resolve_top val
|
5016
|
-
if val
|
5095
|
+
if ::Numeric === val
|
5096
|
+
@y - val
|
5097
|
+
elsif val.end_with? 'vh'
|
5017
5098
|
page_height * (1 - (val.to_f / 100))
|
5018
5099
|
elsif val.end_with? '%'
|
5019
5100
|
@y - effective_page_height * (val.to_f / 100)
|
@@ -5105,20 +5186,17 @@ module Asciidoctor
|
|
5105
5186
|
@label = :scratch
|
5106
5187
|
@save_state = nil
|
5107
5188
|
@scratch_depth = 0
|
5108
|
-
# NOTE: don't need background image in scratch document; can cause marshal error anyway
|
5109
|
-
saved_page_bg_image, @page_bg_image = @page_bg_image, { verso: nil, recto: nil }
|
5110
5189
|
# NOTE: pdfmark has a reference to the Asciidoctor::Document, which we don't want to serialize
|
5111
5190
|
saved_pdfmark, @pdfmark = @pdfmark, nil
|
5112
5191
|
# IMPORTANT: don't set font before using marshal as it causes serialization to fail
|
5113
5192
|
result = yield
|
5114
5193
|
@pdfmark = saved_pdfmark
|
5115
|
-
@page_bg_image = saved_page_bg_image
|
5116
5194
|
@label = :primary
|
5117
5195
|
result
|
5118
5196
|
end
|
5119
5197
|
|
5120
5198
|
def init_scratch originator
|
5121
|
-
if @media == 'prepress' && page_margin != (page_margin_recto = @
|
5199
|
+
if @media == 'prepress' && page_margin != (page_margin_recto = @page_margin[page.layout][:recto])
|
5122
5200
|
# NOTE: prepare scratch document to use page margin from recto side (which has same width as verso side)
|
5123
5201
|
set_page_margin page_margin_recto
|
5124
5202
|
end
|