asciidoctor-pdf 2.0.0.alpha.1 → 2.0.0.beta.1

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +94 -1
  3. data/README.adoc +32 -14
  4. data/data/fonts/ABOUT-mplus1p-subset +1 -0
  5. data/data/fonts/ABOUT-notosans-subset +1 -0
  6. data/data/fonts/ABOUT-notoserif-subset +1 -0
  7. data/data/fonts/mplus1mn-bold-subset.ttf +0 -0
  8. data/data/fonts/mplus1mn-bold_italic-subset.ttf +0 -0
  9. data/data/fonts/mplus1mn-italic-subset.ttf +0 -0
  10. data/data/fonts/mplus1mn-regular-subset.ttf +0 -0
  11. data/data/fonts/mplus1p-regular-fallback.ttf +0 -0
  12. data/data/fonts/notosans-bold-subset.ttf +0 -0
  13. data/data/fonts/notosans-bold_italic-subset.ttf +0 -0
  14. data/data/fonts/notosans-italic-subset.ttf +0 -0
  15. data/data/fonts/notosans-regular-subset.ttf +0 -0
  16. data/data/fonts/notoserif-bold-subset.ttf +0 -0
  17. data/data/fonts/notoserif-bold_italic-subset.ttf +0 -0
  18. data/data/fonts/notoserif-italic-subset.ttf +0 -0
  19. data/data/fonts/notoserif-regular-subset.ttf +0 -0
  20. data/data/themes/base-theme.yml +11 -20
  21. data/data/themes/default-theme.yml +8 -7
  22. data/docs/theming-guide.adoc +11 -10
  23. data/lib/asciidoctor/pdf/converter.rb +445 -305
  24. data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +4 -0
  25. data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +8 -0
  26. data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +117 -38
  27. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +5 -0
  28. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb +13 -0
  29. data/lib/asciidoctor/pdf/ext/prawn/images.rb +6 -2
  30. data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +1 -1
  31. data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
  32. data/lib/asciidoctor/pdf/formatted_text/transform.rb +7 -2
  33. data/lib/asciidoctor/pdf/nogmagick.rb +6 -0
  34. data/lib/asciidoctor/pdf/nopngmagick.rb +3 -0
  35. data/lib/asciidoctor/pdf/optimizer.rb +12 -5
  36. data/lib/asciidoctor/pdf/text_transformer.rb +14 -0
  37. data/lib/asciidoctor/pdf/theme_loader.rb +19 -3
  38. data/lib/asciidoctor/pdf/version.rb +1 -1
  39. metadata +5 -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
@@ -14,6 +14,14 @@ class PDF::Core::Page
14
14
  content.stream.filtered_stream == (@tare_content_stream ||= InitialPageContent) && document.page_number > 0
15
15
  end
16
16
 
17
+ # Flags this page as imported.
18
+ #
19
+ def imported
20
+ @imported_page = true
21
+ end
22
+
23
+ alias imported_page imported
24
+
17
25
  # Reset the content of the page.
18
26
  # Note that this method may leave behind an orphaned background image.
19
27
  def reset_content
@@ -103,7 +103,7 @@ module Asciidoctor
103
103
  NewPageRequiredError = ::Class.new ::StopIteration
104
104
 
105
105
  InhibitNewPageProc = proc do |pdf|
106
- pdf.delete_page
106
+ pdf.delete_current_page
107
107
  raise NewPageRequiredError
108
108
  end
109
109
 
@@ -111,7 +111,7 @@ module Asciidoctor
111
111
 
112
112
  DetectEmptyFirstPageProc = proc do |delegate, pdf|
113
113
  if pdf.state.pages[pdf.page_number - 2].empty?
114
- pdf.delete_page
114
+ pdf.delete_current_page
115
115
  raise NewPageRequiredError
116
116
  end
117
117
  delegate.call pdf if (pdf.state.on_page_create_callback = delegate)
@@ -269,6 +269,20 @@ module Asciidoctor
269
269
  dest_xyz 0, page_height, nil, (page_num ? state.pages[page_num - 1] : page)
270
270
  end
271
271
 
272
+ # Gets the destination registered for the specified name. The return value
273
+ # matches that which was passed to the add_dest method.
274
+ #
275
+ def get_dest name, node = dests.data
276
+ node.children.each do |child|
277
+ if ::PDF::Core::NameTree::Value === child
278
+ return child.value.data if child.name == name
279
+ elsif (found = get_dest name, child)
280
+ return found
281
+ end
282
+ end
283
+ nil
284
+ end
285
+
272
286
  # Fonts
273
287
 
274
288
  # Registers a new custom font described in the data parameter
@@ -495,6 +509,8 @@ module Asciidoctor
495
509
  lowercase_pcdata text
496
510
  when :capitalize, 'capitalize'
497
511
  capitalize_words_pcdata text
512
+ when :smallcaps, 'smallcaps'
513
+ smallcaps_pcdata text
498
514
  else
499
515
  text
500
516
  end
@@ -538,25 +554,34 @@ module Asciidoctor
538
554
  # Example:
539
555
  #
540
556
  # pad_box 20 do
541
- # text 'A paragraph inside a blox with even padding on all sides.'
557
+ # text 'A paragraph inside a blox with even padding from all edges.'
558
+ # end
559
+ #
560
+ # pad_box [10, 5] do
561
+ # text 'A paragraph inside a box with different padding from ends and sides.'
542
562
  # end
543
563
  #
544
- # pad_box [10, 10, 10, 20] do
545
- # text 'An indented paragraph inside a box with equal padding on all sides.'
564
+ # pad_box [5, 10, 15, 20] do
565
+ # text 'A paragraph inside a box with different padding from each edge.'
546
566
  # end
547
567
  #
548
- def pad_box padding
568
+ def pad_box padding, node = nil
549
569
  if padding
550
- # TODO: implement shorthand combinations like in CSS
551
- p_top, p_right, p_bottom, p_left = ::Array === padding ? padding : (::Array.new 4, padding)
570
+ p_top, p_right, p_bottom, p_left = expand_padding_value padding
571
+ # logic is intentionally inlined
552
572
  begin
553
- # logic is intentionally inlined
573
+ if node && ((last_block = node).content_model != :compound || (last_block = node.blocks[-1])&.context == :paragraph)
574
+ @bottom_gutters << { last_block => p_bottom }
575
+ else
576
+ @bottom_gutters << {}
577
+ end
554
578
  move_down p_top
555
579
  bounds.add_left_padding p_left
556
580
  bounds.add_right_padding p_right
557
581
  yield
558
- cursor > p_bottom ? (move_down p_bottom) : reference_bounds.move_past_bottom unless at_page_top?
559
582
  ensure
583
+ cursor > p_bottom ? (move_down p_bottom) : reference_bounds.move_past_bottom unless at_page_top?
584
+ @bottom_gutters.pop
560
585
  bounds.subtract_left_padding p_left
561
586
  bounds.subtract_right_padding p_right
562
587
  end
@@ -570,30 +595,73 @@ module Asciidoctor
570
595
  end
571
596
 
572
597
  def expand_padding_value shorthand
573
- unless (padding = (@side_area_shorthand_cache ||= {})[shorthand])
574
- if ::Array === shorthand
575
- case shorthand.size
598
+ (@edge_shorthand_cache ||= ::Hash.new do |store, key|
599
+ if ::Array === key
600
+ case key.size
576
601
  when 1
577
- padding = [shorthand[0], shorthand[0], shorthand[0], shorthand[0]]
602
+ value = [(value0 = key[0] || 0), value0, value0, value0]
578
603
  when 2
579
- padding = [shorthand[0], shorthand[1], shorthand[0], shorthand[1]]
604
+ value = [(value0 = key[0] || 0), (value1 = key[1] || 0), value0, value1]
580
605
  when 3
581
- padding = [shorthand[0], shorthand[1], shorthand[2], shorthand[1]]
606
+ value = [key[0] || 0, (value1 = key[1] || 0), key[2] || 0, value1]
582
607
  when 4
583
- padding = shorthand
608
+ value = key.map {|it| it || 0 }
584
609
  else
585
- padding = shorthand.slice 0, 4
610
+ value = (key.slice 0, 4).map {|it| it || 0 }
586
611
  end
587
612
  else
588
- padding = ::Array.new 4, (shorthand || 0)
613
+ value = [(value0 = key || 0), value0, value0, value0]
589
614
  end
590
- @side_area_shorthand_cache[shorthand] = padding
591
- end
592
- padding.dup
615
+ store[key] = value
616
+ end)[shorthand]
593
617
  end
594
618
 
595
619
  alias expand_margin_value expand_padding_value
596
620
 
621
+ def expand_grid_values shorthand, default = nil
622
+ if ::Array === shorthand
623
+ case shorthand.size
624
+ when 1
625
+ [(value0 = shorthand[0] || default), value0]
626
+ when 2
627
+ shorthand.map {|it| it || default }
628
+ when 4
629
+ if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand
630
+ [shorthand, shorthand]
631
+ else
632
+ (shorthand.slice 0, 2).map {|it| it || default }
633
+ end
634
+ else
635
+ (shorthand.slice 0, 2).map {|it| it || default }
636
+ end
637
+ else
638
+ [(value0 = shorthand || default), value0]
639
+ end
640
+ end
641
+
642
+ def expand_rect_values shorthand, default = nil
643
+ if ::Array === shorthand
644
+ case shorthand.size
645
+ when 1
646
+ [(value0 = shorthand[0] || default), value0, value0, value0]
647
+ when 2
648
+ [(value0 = shorthand[0] || default), (value1 = shorthand[1] || default), value0, value1]
649
+ when 3
650
+ [shorthand[0] || default, (value1 = shorthand[1] || default), shorthand[2] || default, value1]
651
+ when 4
652
+ if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand
653
+ [shorthand, shorthand, shorthand, shorthand]
654
+ else
655
+ shorthand.map {|it| it || default }
656
+ end
657
+ else
658
+ (shorthand.slice 0, 4).map {|it| it || default }
659
+ end
660
+ else
661
+ [(value0 = shorthand || default), value0, value0, value0]
662
+ end
663
+ end
664
+
597
665
  # Stretch the current bounds to the left and right edges of the current page
598
666
  # while yielding the specified block if the verdict argument is true.
599
667
  # Otherwise, simply yield the specified block.
@@ -650,7 +718,8 @@ module Asciidoctor
650
718
  def fill_and_stroke_bounds f_color = fill_color, s_color = stroke_color, options = {}
651
719
  no_fill = !f_color || f_color == 'transparent'
652
720
  if ::Array === (s_width = options[:line_width] || 0)
653
- s_width_max = s_width.map(&:to_i).max
721
+ s_width = [s_width[0], s_width[1], s_width[0], s_width[1]] if s_width.size == 2
722
+ s_width_max = (s_width = s_width.map {|it| it || 0 }).max
654
723
  radius = 0
655
724
  else
656
725
  radius = options[:radius] || 0
@@ -668,13 +737,19 @@ module Asciidoctor
668
737
 
669
738
  # stroke
670
739
  if s_width_max
671
- if (s_width_end = s_width[0] || 0) > 0
672
- stroke_horizontal_rule s_color, line_width: s_width_end, line_style: options[:line_style]
673
- stroke_horizontal_rule s_color, line_width: s_width_end, line_style: options[:line_style], at: bounds.height
740
+ s_width_top, s_width_right, s_width_bottom, s_width_left = s_width
741
+ projection_top, projection_right, projection_bottom, projection_left = s_width.map {|it| it * 0.5 }
742
+ if s_width_top > 0
743
+ stroke_horizontal_rule s_color, line_width: s_width_top, line_style: options[:line_style], left_projection: projection_left, right_projection: projection_right
744
+ end
745
+ if s_width_right > 0
746
+ stroke_vertical_rule s_color, line_width: s_width_right, line_style: options[:line_style], at: bounds.width, top_projection: projection_top, bottom_projection: projection_bottom
747
+ end
748
+ if s_width_bottom > 0
749
+ stroke_horizontal_rule s_color, line_width: s_width_bottom, line_style: options[:line_style], at: bounds.height, left_projection: projection_left, right_projection: projection_right
674
750
  end
675
- if (s_width_side = s_width[1] || 0) > 0
676
- stroke_vertical_rule s_color, line_width: s_width_side, line_style: options[:line_style]
677
- stroke_vertical_rule s_color, line_width: s_width_side, line_style: options[:line_style], at: bounds.width
751
+ if s_width_left > 0
752
+ stroke_vertical_rule s_color, line_width: s_width_left, line_style: options[:line_style], top_projection: projection_top, bottom_projection: projection_bottom
678
753
  end
679
754
  else
680
755
  stroke_color s_color
@@ -709,8 +784,8 @@ module Asciidoctor
709
784
  rule_y = cursor - (options[:at] || 0)
710
785
  rule_style = options[:line_style]
711
786
  rule_width = options[:line_width] || 0.5
712
- rule_x_start = bounds.left
713
- rule_x_end = bounds.right
787
+ rule_x_start = bounds.left - (options[:left_projection] || 0)
788
+ rule_x_end = bounds.right - (options[:right_projection] || 0)
714
789
  save_graphics_state do
715
790
  stroke_color rule_color
716
791
  case rule_style
@@ -740,8 +815,8 @@ module Asciidoctor
740
815
  #
741
816
  def stroke_vertical_rule rule_color = stroke_color, options = {}
742
817
  rule_x = options[:at] || 0
743
- rule_y_from = bounds.top
744
- rule_y_to = bounds.bottom
818
+ rule_y_from = bounds.top + (options[:top_projection] || 0)
819
+ rule_y_to = bounds.bottom - (options[:bottom_projection] || 0)
745
820
  rule_style = options[:line_style]
746
821
  rule_width = options[:line_width] || 0.5
747
822
  save_graphics_state do
@@ -764,10 +839,15 @@ module Asciidoctor
764
839
 
765
840
  # Deletes the current page and move the cursor
766
841
  # to the previous page.
767
- def delete_page
842
+ def delete_current_page
768
843
  pg = page_number
769
844
  pdf_store = state.store
770
845
  content_id = page.content.identifier
846
+ page_ref = page.dictionary
847
+ (prune_dests = proc do |node|
848
+ node.children.delete_if {|it| ::PDF::Core::NameTree::Node === it ? prune_dests[it] : it.value.data[0] == page_ref }
849
+ false
850
+ end)[dests.data]
771
851
  # NOTE: cannot delete objects and IDs, otherwise references get corrupted; so just reset the value
772
852
  (pdf_store.instance_variable_get :@objects)[content_id] = ::PDF::Core::Reference.new content_id, {}
773
853
  pdf_store.pages.data[:Kids].pop
@@ -793,7 +873,7 @@ module Asciidoctor
793
873
  prev_page_size = page.size
794
874
  state.compress = false if state.compress # can't use compression if using template
795
875
  prev_text_rendering_mode = (defined? @text_rendering_mode) ? @text_rendering_mode : nil
796
- delete_page if options[:replace]
876
+ delete_current_page if options[:replace]
797
877
  # NOTE: use functionality provided by prawn-templates
798
878
  start_new_page_discretely template: file, template_page: options[:page]
799
879
  # prawn-templates sets text_rendering_mode to :unknown, which breaks running content; revert
@@ -805,11 +885,11 @@ module Asciidoctor
805
885
  # way atm to prevent the size & layout of the imported page from affecting subsequent pages
806
886
  advance_page size: prev_page_size, layout: prev_page_layout if options.fetch :advance, true
807
887
  elsif options.fetch :advance_if_missing, true
808
- delete_page
888
+ delete_current_page
809
889
  # NOTE: see previous comment
810
890
  advance_page size: prev_page_size, layout: prev_page_layout
811
891
  else
812
- delete_page
892
+ delete_current_page
813
893
  end
814
894
  nil
815
895
  end
@@ -866,7 +946,6 @@ module Asciidoctor
866
946
  def scratch?
867
947
  @label == :scratch
868
948
  end
869
- alias is_scratch? scratch?
870
949
 
871
950
  def with_dry_run &block
872
951
  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
@@ -99,7 +99,7 @@ module Prawn
99
99
  apply_font_properties { pdf.traverse content }
100
100
  if (extra_pages = pdf.page_number - start_page) > 0
101
101
  logger.error %(the table cell on page #{start_page} has been truncated; Asciidoctor PDF does not support table cell content that exceeds the height of a single page) unless extra_pages == 1 && pdf.page.empty?
102
- extra_pages.times { pdf.delete_page }
102
+ extra_pages.times { pdf.delete_current_page }
103
103
  end
104
104
  nil
105
105
  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.chomp ' '
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, (build_fragment parent, tag_name, attributes)
171
+ apply pcdata, fragments, fragment
167
172
  previous_fragment_is_text = false
168
173
  end
169
174
  # case 2: void element
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined? GMagick::Image
4
+ Prawn.image_handler.unregister Gmagick
5
+ Prawn.image_handler.register! Prawn::Images::PNG
6
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Prawn.image_handler.register! Prawn::Images::PNG if defined? GMagick::Image
@@ -40,9 +40,10 @@ module Asciidoctor
40
40
  attr_reader :quality
41
41
  attr_reader :compatibility_level
42
42
 
43
- def initialize quality = 'default', compatibility_level = '1.4'
43
+ def initialize quality = 'default', compatibility_level = '1.4', compliance = 'PDF'
44
44
  @quality = QUALITY_NAMES[quality]
45
45
  @compatibility_level = compatibility_level
46
+ @compliance = compliance
46
47
  if (gs_path = ::ENV['GS'])
47
48
  ::RGhost::Config::GS[:path] = gs_path
48
49
  end
@@ -57,10 +58,16 @@ module Asciidoctor
57
58
  else
58
59
  inputs = target
59
60
  end
60
- (::RGhost::Convert.new inputs).to :pdf,
61
- filename: filename_tmp.to_s,
62
- quality: @quality,
63
- d: { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
61
+ d = { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
62
+ case @compliance
63
+ when 'PDF/A', 'PDF/A-1', 'PDF/A-2', 'PDF/A-3'
64
+ d[:PDFA] = ((@compliance.split '-', 2)[1] || 1).to_i
65
+ d[:ShowAnnots] = false
66
+ when 'PDF/X', 'PDF/X-1', 'PDF/X-3'
67
+ d[:PDFX] = true
68
+ d[:ShowAnnots] = false
69
+ end
70
+ (::RGhost::Convert.new inputs).to :pdf, filename: filename_tmp.to_s, quality: @quality, d: d
64
71
  filename_o.binwrite filename_tmp.binread
65
72
  end
66
73
  nil
@@ -10,6 +10,12 @@ module Asciidoctor
10
10
  WordRx = /\p{Word}+/
11
11
  Hyphen = '-'
12
12
  SoftHyphen = ?\u00ad
13
+ LowerAlphaChars = 'a-z'
14
+ # NOTE: use more widely-supported ғ instead of ꜰ as replacement for F
15
+ # NOTE: use more widely-supported ǫ instead of ꞯ as replacement for Q
16
+ # NOTE: use more widely-supported s (lowercase latin "s") instead of ꜱ as replacement for S
17
+ # NOTE: in small caps, x (lowercase latin "x") remains unchanged
18
+ SmallCapsChars = 'ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴoᴘǫʀsᴛᴜᴠᴡxʏᴢ'
13
19
 
14
20
  def capitalize_words_pcdata string
15
21
  if XMLMarkupRx.match? string
@@ -50,6 +56,14 @@ module Asciidoctor
50
56
  string.upcase
51
57
  end
52
58
  end
59
+
60
+ def smallcaps_pcdata string
61
+ if XMLMarkupRx.match? string
62
+ string.gsub(PCDATAFilterRx) { $2 ? ($2.tr LowerAlphaChars, SmallCapsChars) : $1 }
63
+ else
64
+ string.tr LowerAlphaChars, SmallCapsChars
65
+ end
66
+ end
53
67
  end
54
68
  end
55
69
  end
@@ -15,6 +15,10 @@ module Asciidoctor
15
15
  BaseThemePath = ::File.join ThemesDir, 'base-theme.yml'
16
16
  BundledThemeNames = (::Dir.children ThemesDir).map {|it| it.slice 0, it.length - 10 }
17
17
  DeprecatedCategoryKeys = { 'blockquote' => 'quote', 'key' => 'kbd', 'literal' => 'codespan', 'outline_list' => 'list' }
18
+ DeprecatedKeys = %w(base heading heading_h1 heading_h2 heading_h3 heading_h4 heading_h5 heading_h6 title_page abstract abstract_title admonition_label sidebar_title toc_title).each_with_object({ 'table_caption_side' => 'table_caption_end' }) do |prefix, accum|
19
+ accum[%(#{prefix}_align)] = %(#{prefix}_text_align)
20
+ end
21
+ PaddingBottomHackKeys = %w(example_padding quote_padding sidebar_padding verse_padding)
18
22
 
19
23
  VariableRx = /\$([a-z0-9_-]+)/
20
24
  LoneVariableRx = /^\$([a-z0-9_-]+)$/
@@ -22,6 +26,7 @@ module Asciidoctor
22
26
  MultiplyDivideOpRx = %r((-?\d+(?:\.\d+)?) +([*/^]) +(-?\d+(?:\.\d+)?))
23
27
  AddSubtractOpRx = /(-?\d+(?:\.\d+)?) +([+\-]) +(-?\d+(?:\.\d+)?)/
24
28
  PrecisionFuncRx = /^(round|floor|ceil)\(/
29
+ RoleAlignKeyRx = /(?:_text)?_align$/
25
30
 
26
31
  module ColorValue; end
27
32
 
@@ -77,7 +82,7 @@ module Asciidoctor
77
82
  else
78
83
  theme_data = load_file theme_path, nil, theme_dir
79
84
  unless (::File.dirname theme_path) == ThemesDir
80
- theme_data.base_align ||= 'left'
85
+ theme_data.base_text_align ||= 'left'
81
86
  theme_data.base_line_height ||= 1
82
87
  theme_data.base_font_color ||= '000000'
83
88
  theme_data.code_font_family ||= (theme_data.codespan_font_family || 'Courier')
@@ -166,9 +171,19 @@ module Asciidoctor
166
171
  val.each do |subkey, subval|
167
172
  process_entry %(#{key}_#{key == 'role' || !(subkey.include? '-') ? subkey : (subkey.tr '-', '_')}), subval, data
168
173
  end
174
+ elsif (rekey = DeprecatedKeys[key]) ||
175
+ ((key.start_with? 'role_') && (key.end_with? '_align') && (rekey = key.sub RoleAlignKeyRx, '_text_align'))
176
+ data[rekey] = evaluate val, data
177
+ elsif PaddingBottomHackKeys.include? key
178
+ val = evaluate val, data
179
+ # normalize padding hacks for themes designed before the converter had smart margins
180
+ val[2] = val[0] if ::Array === val && val[0].to_f >= 0 && val[2].to_f <= 0
181
+ data[key] = val
169
182
  # QUESTION: do we really need to evaluate_math in this case?
170
183
  elsif key.end_with? '_color'
171
- if key == 'table_grid_color' && (Array val).size == 2
184
+ if key == 'table_border_color'
185
+ data[key] = ::Array === val ? val.map {|it| to_color evaluate it, data } : (to_color evaluate val, data)
186
+ elsif key == 'table_grid_color' && ::Array === val && val.size == 2
172
187
  data[key] = val.map {|it| to_color evaluate it, data }
173
188
  else
174
189
  data[key] = to_color evaluate val, data
@@ -206,7 +221,8 @@ module Asciidoctor
206
221
  def resolve_var vars, ref, var
207
222
  var = var.tr '-', '_' if var.include? '-'
208
223
  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) }
224
+ DeprecatedCategoryKeys.any? {|old, new| (var.start_with? old + '_') && (vars.respond_to? (replace = new + (var.slice old.length, var.length))) && (var = replace) } ||
225
+ ((replace = DeprecatedKeys[var]) && (vars.respond_to? replace) && (var = replace))
210
226
  vars[var]
211
227
  else
212
228
  logger.warn %(unknown variable reference in PDF theme: #{ref})
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.0.0.alpha.1'
5
+ VERSION = '2.0.0.beta.1'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha.1
4
+ version: 2.0.0.beta.1
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-20 00:00:00.000000000 Z
12
+ date: 2022-05-04 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,8 @@ 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
294
+ - lib/asciidoctor/pdf/nopngmagick.rb
292
295
  - lib/asciidoctor/pdf/optimizer.rb
293
296
  - lib/asciidoctor/pdf/pdfmark.rb
294
297
  - lib/asciidoctor/pdf/roman_numeral.rb