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

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