asciidoctor-pdf 2.1.5 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|