asciidoctor-pdf 2.0.0.alpha.1 → 2.0.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +38 -1
- data/README.adoc +3 -3
- data/data/themes/base-theme.yml +3 -2
- data/data/themes/default-theme.yml +6 -5
- data/docs/theming-guide.adoc +3 -3
- data/lib/asciidoctor/pdf/converter.rb +282 -208
- data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +4 -0
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +57 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +5 -0
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb +13 -0
- data/lib/asciidoctor/pdf/ext/prawn/images.rb +6 -2
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +7 -2
- data/lib/asciidoctor/pdf/nogmagick.rb +6 -0
- data/lib/asciidoctor/pdf/theme_loader.rb +13 -3
- data/lib/asciidoctor/pdf/version.rb +1 -1
- metadata +4 -2
@@ -11,6 +11,10 @@ class Asciidoctor::Document
|
|
11
11
|
preface.sectname = 'preface'
|
12
12
|
preface.title = blk0.instance_variable_get :@title
|
13
13
|
preface.id = preface.generate_id
|
14
|
+
if (first_child = blk0.blocks[0])&.option? 'notitle'
|
15
|
+
preface.set_option 'notitle'
|
16
|
+
first_child.role = 'lead' if first_child.context == :paragraph && !first_child.role?
|
17
|
+
end
|
14
18
|
preface.blocks.replace (blk0.blocks.map do |b|
|
15
19
|
b.parent = preface
|
16
20
|
b
|
@@ -545,18 +545,24 @@ module Asciidoctor
|
|
545
545
|
# text 'An indented paragraph inside a box with equal padding on all sides.'
|
546
546
|
# end
|
547
547
|
#
|
548
|
-
def pad_box padding
|
548
|
+
def pad_box padding, node = nil
|
549
549
|
if padding
|
550
550
|
# TODO: implement shorthand combinations like in CSS
|
551
551
|
p_top, p_right, p_bottom, p_left = ::Array === padding ? padding : (::Array.new 4, padding)
|
552
|
+
# logic is intentionally inlined
|
552
553
|
begin
|
553
|
-
|
554
|
+
if node && ((last_block = node).content_model != :compound || (last_block = node.blocks[-1])&.context == :paragraph)
|
555
|
+
@bottom_gutters << { last_block => p_bottom }
|
556
|
+
else
|
557
|
+
@bottom_gutters << {}
|
558
|
+
end
|
554
559
|
move_down p_top
|
555
560
|
bounds.add_left_padding p_left
|
556
561
|
bounds.add_right_padding p_right
|
557
562
|
yield
|
558
563
|
cursor > p_bottom ? (move_down p_bottom) : reference_bounds.move_past_bottom unless at_page_top?
|
559
564
|
ensure
|
565
|
+
@bottom_gutters.pop
|
560
566
|
bounds.subtract_left_padding p_left
|
561
567
|
bounds.subtract_right_padding p_right
|
562
568
|
end
|
@@ -594,6 +600,50 @@ module Asciidoctor
|
|
594
600
|
|
595
601
|
alias expand_margin_value expand_padding_value
|
596
602
|
|
603
|
+
def expand_grid_values shorthand, default = nil
|
604
|
+
if ::Array === shorthand
|
605
|
+
case shorthand.size
|
606
|
+
when 1
|
607
|
+
[(value0 = shorthand[0] || default), value0]
|
608
|
+
when 2
|
609
|
+
shorthand.map {|it| it || default }
|
610
|
+
when 4
|
611
|
+
if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand
|
612
|
+
[shorthand, shorthand]
|
613
|
+
else
|
614
|
+
(shorthand.slice 0, 2).map {|it| it || default }
|
615
|
+
end
|
616
|
+
else
|
617
|
+
(shorthand.slice 0, 2).map {|it| it || default }
|
618
|
+
end
|
619
|
+
else
|
620
|
+
[(value0 = shorthand || default), value0]
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
def expand_rect_values shorthand, default = nil
|
625
|
+
if ::Array === shorthand
|
626
|
+
case shorthand.size
|
627
|
+
when 1
|
628
|
+
[(value0 = shorthand[0] || default), value0, value0, value0]
|
629
|
+
when 2
|
630
|
+
[(value0 = shorthand[0] || default), (value1 = shorthand[1] || default), value0, value1]
|
631
|
+
when 3
|
632
|
+
[shorthand[0] || default, (value1 = shorthand[1] || default), shorthand[2] || default, value1]
|
633
|
+
when 4
|
634
|
+
if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand
|
635
|
+
[shorthand, shorthand, shorthand, shorthand]
|
636
|
+
else
|
637
|
+
shorthand.map {|it| it || default }
|
638
|
+
end
|
639
|
+
else
|
640
|
+
(shorthand.slice 0, 4).map {|it| it || default }
|
641
|
+
end
|
642
|
+
else
|
643
|
+
[(value0 = shorthand || default), value0, value0, value0]
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
597
647
|
# Stretch the current bounds to the left and right edges of the current page
|
598
648
|
# while yielding the specified block if the verdict argument is true.
|
599
649
|
# Otherwise, simply yield the specified block.
|
@@ -768,6 +818,11 @@ module Asciidoctor
|
|
768
818
|
pg = page_number
|
769
819
|
pdf_store = state.store
|
770
820
|
content_id = page.content.identifier
|
821
|
+
page_ref = page.dictionary
|
822
|
+
(prune_dests = proc do |node|
|
823
|
+
node.children.delete_if {|it| ::PDF::Core::NameTree::Node === it ? prune_dests[it] : it.value.data[0] == page_ref }
|
824
|
+
false
|
825
|
+
end)[dests.data]
|
771
826
|
# NOTE: cannot delete objects and IDs, otherwise references get corrupted; so just reset the value
|
772
827
|
(pdf_store.instance_variable_get :@objects)[content_id] = ::PDF::Core::Reference.new content_id, {}
|
773
828
|
pdf_store.pages.data[:Kids].pop
|
@@ -866,7 +921,6 @@ module Asciidoctor
|
|
866
921
|
def scratch?
|
867
922
|
@label == :scratch
|
868
923
|
end
|
869
|
-
alias is_scratch? scratch?
|
870
924
|
|
871
925
|
def with_dry_run &block
|
872
926
|
yield dry_run(&block).position_onto self, cursor
|
@@ -6,6 +6,11 @@ Prawn::Text::Formatted::Box.prepend (Module.new do
|
|
6
6
|
def initialize formatted_text, options = {}
|
7
7
|
super
|
8
8
|
formatted_text[0][:normalize_line_height] = true if options[:normalize_line_height] && !formatted_text.empty?
|
9
|
+
options[:extensions]&.each {|extension| extend extension }
|
10
|
+
if (bottom_gutter = options[:bottom_gutter]) && bottom_gutter > 0
|
11
|
+
@bottom_gutter = bottom_gutter
|
12
|
+
extend Prawn::Text::Formatted::ProtectBottomGutter
|
13
|
+
end
|
9
14
|
end
|
10
15
|
|
11
16
|
def draw_fragment_overlay_styles fragment
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn::Text::Formatted::ProtectBottomGutter
|
4
|
+
def enough_height_for_this_line?
|
5
|
+
return super unless @arranger.finished?
|
6
|
+
begin
|
7
|
+
@height -= @bottom_gutter
|
8
|
+
super
|
9
|
+
ensure
|
10
|
+
@height += @bottom_gutter
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -13,14 +13,18 @@ module Asciidoctor
|
|
13
13
|
#opts[:cache_images] = cache_uri if !(opts.key? :cache_images) && (respond_to? :cache_uri)
|
14
14
|
#opts[:fallback_font_name] = fallback_svg_font_name if !(opts.key? :fallback_font_name) && (respond_to? :fallback_svg_font_name)
|
15
15
|
if (fit = opts.delete :fit) && !(opts[:width] || opts[:height])
|
16
|
-
svg (::File.read file, mode: 'r:UTF-8'), opts do |svg_doc|
|
16
|
+
image_info = svg (::File.read file, mode: 'r:UTF-8'), opts do |svg_doc|
|
17
17
|
# NOTE: fit to specified width, then reduce size if height exceeds bounds
|
18
18
|
svg_doc.calculate_sizing requested_width: fit[0] if svg_doc.sizing.output_width != fit[0]
|
19
19
|
svg_doc.calculate_sizing requested_height: fit[1] if svg_doc.sizing.output_height > fit[1]
|
20
20
|
end
|
21
21
|
else
|
22
|
-
svg (::File.read file, mode: 'r:UTF-8'), opts
|
22
|
+
image_info = svg (::File.read file, mode: 'r:UTF-8'), opts
|
23
23
|
end
|
24
|
+
if ::Asciidoctor::Logging === self && !scratch? && !(warnings = image_info[:warnings]).empty?
|
25
|
+
warnings.each {|warning| log :warn, %(problem encountered in image: #{file}; #{warning}) }
|
26
|
+
end
|
27
|
+
image_info
|
24
28
|
else
|
25
29
|
::File.open(file, 'rb') {|fd| super fd, opts }
|
26
30
|
end
|
@@ -7,4 +7,5 @@ require_relative 'prawn/images'
|
|
7
7
|
require_relative 'prawn/formatted_text/arranger'
|
8
8
|
require_relative 'prawn/formatted_text/box'
|
9
9
|
require_relative 'prawn/formatted_text/fragment'
|
10
|
+
require_relative 'prawn/formatted_text/protect_bottom_gutter'
|
10
11
|
require_relative 'prawn/extensions'
|
@@ -156,14 +156,19 @@ module Asciidoctor
|
|
156
156
|
if (pcdata = node[:pcdata]).empty?
|
157
157
|
# QUESTION: should this be handled by the formatter after the transform is complete?
|
158
158
|
if previous_fragment_is_text && ((previous_fragment_text = fragments[-1][:text]).end_with? ' ')
|
159
|
-
fragments[-1][:text] = previous_fragment_text.
|
159
|
+
fragments[-1][:text] = previous_fragment_text.chop
|
160
160
|
end
|
161
161
|
else
|
162
162
|
tag_name = node[:name]
|
163
163
|
attributes = node[:attributes]
|
164
164
|
parent = clone_fragment inherited
|
165
|
+
fragment = build_fragment parent, tag_name, attributes
|
166
|
+
if tag_name == :a && fragment[:type] == :indexterm && !attributes[:visible] &&
|
167
|
+
previous_fragment_is_text && ((previous_fragment_text = fragments[-1][:text]).end_with? ' ')
|
168
|
+
fragments[-1][:text] = previous_fragment_text.chop
|
169
|
+
end
|
165
170
|
# NOTE: decorate child fragments with inherited properties from this element
|
166
|
-
apply pcdata, fragments,
|
171
|
+
apply pcdata, fragments, fragment
|
167
172
|
previous_fragment_is_text = false
|
168
173
|
end
|
169
174
|
# case 2: void element
|
@@ -15,6 +15,9 @@ module Asciidoctor
|
|
15
15
|
BaseThemePath = ::File.join ThemesDir, 'base-theme.yml'
|
16
16
|
BundledThemeNames = (::Dir.children ThemesDir).map {|it| it.slice 0, it.length - 10 }
|
17
17
|
DeprecatedCategoryKeys = { 'blockquote' => 'quote', 'key' => 'kbd', 'literal' => 'codespan', 'outline_list' => 'list' }
|
18
|
+
AmbiguousAlignKeys = %w(base heading heading_h1 heading_h2 heading_h3 heading_h4 heading_h5 heading_h6 title_page abstract abstract_title admonition_label sidebar_title toc_title).each_with_object({}) do |prefix, accum|
|
19
|
+
accum[%(#{prefix}_align)] = %(#{prefix}_text_align)
|
20
|
+
end
|
18
21
|
|
19
22
|
VariableRx = /\$([a-z0-9_-]+)/
|
20
23
|
LoneVariableRx = /^\$([a-z0-9_-]+)$/
|
@@ -22,6 +25,7 @@ module Asciidoctor
|
|
22
25
|
MultiplyDivideOpRx = %r((-?\d+(?:\.\d+)?) +([*/^]) +(-?\d+(?:\.\d+)?))
|
23
26
|
AddSubtractOpRx = /(-?\d+(?:\.\d+)?) +([+\-]) +(-?\d+(?:\.\d+)?)/
|
24
27
|
PrecisionFuncRx = /^(round|floor|ceil)\(/
|
28
|
+
RoleAlignKeyRx = /(?:_text)?_align$/
|
25
29
|
|
26
30
|
module ColorValue; end
|
27
31
|
|
@@ -77,7 +81,7 @@ module Asciidoctor
|
|
77
81
|
else
|
78
82
|
theme_data = load_file theme_path, nil, theme_dir
|
79
83
|
unless (::File.dirname theme_path) == ThemesDir
|
80
|
-
theme_data.
|
84
|
+
theme_data.base_text_align ||= 'left'
|
81
85
|
theme_data.base_line_height ||= 1
|
82
86
|
theme_data.base_font_color ||= '000000'
|
83
87
|
theme_data.code_font_family ||= (theme_data.codespan_font_family || 'Courier')
|
@@ -166,9 +170,14 @@ module Asciidoctor
|
|
166
170
|
val.each do |subkey, subval|
|
167
171
|
process_entry %(#{key}_#{key == 'role' || !(subkey.include? '-') ? subkey : (subkey.tr '-', '_')}), subval, data
|
168
172
|
end
|
173
|
+
elsif (rekey = AmbiguousAlignKeys[key]) ||
|
174
|
+
((key.start_with? 'role_') && (key.end_with? '_align') && (rekey = key.sub RoleAlignKeyRx, '_text_align'))
|
175
|
+
data[rekey] = evaluate val, data
|
169
176
|
# QUESTION: do we really need to evaluate_math in this case?
|
170
177
|
elsif key.end_with? '_color'
|
171
|
-
if key == '
|
178
|
+
if key == 'table_border_color'
|
179
|
+
data[key] = ::Array === val ? val.map {|it| to_color evaluate it, data } : (to_color evaluate val, data)
|
180
|
+
elsif key == 'table_grid_color' && ::Array === val && val.size == 2
|
172
181
|
data[key] = val.map {|it| to_color evaluate it, data }
|
173
182
|
else
|
174
183
|
data[key] = to_color evaluate val, data
|
@@ -206,7 +215,8 @@ module Asciidoctor
|
|
206
215
|
def resolve_var vars, ref, var
|
207
216
|
var = var.tr '-', '_' if var.include? '-'
|
208
217
|
if (vars.respond_to? var) ||
|
209
|
-
DeprecatedCategoryKeys.any? {|old, new| (var.start_with? old + '_') && (vars.respond_to? (replace = new + (var.slice old.length, var.length))) && (var = replace) }
|
218
|
+
DeprecatedCategoryKeys.any? {|old, new| (var.start_with? old + '_') && (vars.respond_to? (replace = new + (var.slice old.length, var.length))) && (var = replace) } ||
|
219
|
+
((replace = AmbiguousAlignKeys[var]) && (vars.respond_to? replace) && (var = replace))
|
210
220
|
vars[var]
|
211
221
|
else
|
212
222
|
logger.warn %(unknown variable reference in PDF theme: #{ref})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asciidoctor-pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.alpha.
|
4
|
+
version: 2.0.0.alpha.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Allen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-04-
|
12
|
+
date: 2022-04-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|
@@ -270,6 +270,7 @@ files:
|
|
270
270
|
- lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb
|
271
271
|
- lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb
|
272
272
|
- lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb
|
273
|
+
- lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb
|
273
274
|
- lib/asciidoctor/pdf/ext/prawn/images.rb
|
274
275
|
- lib/asciidoctor/pdf/ext/pygments.rb
|
275
276
|
- lib/asciidoctor/pdf/ext/rouge.rb
|
@@ -289,6 +290,7 @@ files:
|
|
289
290
|
- lib/asciidoctor/pdf/formatted_text/transform.rb
|
290
291
|
- lib/asciidoctor/pdf/index_catalog.rb
|
291
292
|
- lib/asciidoctor/pdf/measurements.rb
|
293
|
+
- lib/asciidoctor/pdf/nogmagick.rb
|
292
294
|
- lib/asciidoctor/pdf/optimizer.rb
|
293
295
|
- lib/asciidoctor/pdf/pdfmark.rb
|
294
296
|
- lib/asciidoctor/pdf/roman_numeral.rb
|