asciidoctor-pdf 1.6.2 → 2.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.adoc +224 -30
  4. data/NOTICE.adoc +16 -4
  5. data/README.adoc +207 -67
  6. data/asciidoctor-pdf.gemspec +3 -7
  7. data/data/fonts/ABOUT-mplus1mn-subset +1 -1
  8. data/data/fonts/ABOUT-mplus1p-subset +2 -2
  9. data/data/fonts/ABOUT-notosans-subset +26 -0
  10. data/data/fonts/ABOUT-notoserif-subset +1 -1
  11. data/data/fonts/{LICENSE-notoserif → LICENSE-noto} +0 -0
  12. data/data/fonts/mplus1mn-bold-subset.ttf +0 -0
  13. data/data/fonts/mplus1mn-bold_italic-subset.ttf +0 -0
  14. data/data/fonts/mplus1mn-italic-subset.ttf +0 -0
  15. data/data/fonts/mplus1mn-regular-subset.ttf +0 -0
  16. data/data/fonts/mplus1p-regular-fallback.ttf +0 -0
  17. data/data/fonts/notoemoji-subset.ttf +0 -0
  18. data/data/fonts/notosans-bold-subset.ttf +0 -0
  19. data/data/fonts/notosans-bold_italic-subset.ttf +0 -0
  20. data/data/fonts/notosans-italic-subset.ttf +0 -0
  21. data/data/fonts/notosans-regular-subset.ttf +0 -0
  22. data/data/fonts/notoserif-bold-subset.ttf +0 -0
  23. data/data/fonts/notoserif-bold_italic-subset.ttf +0 -0
  24. data/data/fonts/notoserif-italic-subset.ttf +0 -0
  25. data/data/fonts/notoserif-regular-subset.ttf +0 -0
  26. data/data/themes/base-theme.yml +18 -22
  27. data/data/themes/default-for-print-theme.yml +24 -0
  28. data/data/themes/default-for-print-with-fallback-font-theme.yml +3 -0
  29. data/data/themes/default-theme.yml +49 -54
  30. data/data/themes/default-with-fallback-font-theme.yml +2 -2
  31. data/data/themes/sans-with-fallback-font-theme.yml +10 -0
  32. data/docs/theming-guide.adoc +967 -344
  33. data/lib/asciidoctor/pdf/converter.rb +1691 -1478
  34. data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +18 -1
  35. data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +9 -15
  36. data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +6 -13
  37. data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +3 -16
  38. data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -5
  39. data/lib/asciidoctor/pdf/ext/core/file.rb +1 -1
  40. data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +1 -4
  41. data/lib/asciidoctor/pdf/ext/core/string.rb +2 -2
  42. data/lib/asciidoctor/pdf/ext/core.rb +1 -4
  43. data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +8 -33
  44. data/lib/asciidoctor/pdf/ext/pdf-core.rb +0 -18
  45. data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +5 -7
  46. data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +433 -329
  47. data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +0 -4
  48. data/lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb +1 -1
  49. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +33 -3
  50. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +20 -14
  51. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +9 -3
  52. data/lib/asciidoctor/pdf/ext/prawn/images.rb +14 -16
  53. data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb +6 -0
  54. data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb +22 -0
  55. data/lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb +13 -0
  56. data/lib/asciidoctor/pdf/ext/prawn-svg.rb +5 -2
  57. data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +76 -20
  58. data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +39 -1
  59. data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +21 -15
  60. data/lib/asciidoctor/pdf/ext/prawn-table.rb +1 -1
  61. data/lib/asciidoctor/pdf/ext/pygments.rb +2 -2
  62. data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +17 -20
  63. data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
  64. data/lib/asciidoctor/pdf/ext/rouge.rb +0 -1
  65. data/lib/asciidoctor/pdf/formatted_text/formatter.rb +2 -2
  66. data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +8 -10
  67. data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +69 -78
  68. data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +7 -10
  69. data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +2 -4
  70. data/lib/asciidoctor/pdf/formatted_text/parser.rb +53 -47
  71. data/lib/asciidoctor/pdf/formatted_text/parser.treetop +5 -7
  72. data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +14 -14
  73. data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +4 -7
  74. data/lib/asciidoctor/pdf/formatted_text/transform.rb +116 -109
  75. data/lib/asciidoctor/pdf/formatted_text.rb +0 -1
  76. data/lib/asciidoctor/pdf/index_catalog.rb +7 -11
  77. data/lib/asciidoctor/pdf/optimizer.rb +3 -5
  78. data/lib/asciidoctor/pdf/pdfmark.rb +16 -8
  79. data/lib/asciidoctor/pdf/roman_numeral.rb +4 -22
  80. data/lib/asciidoctor/pdf/sanitizer.rb +18 -13
  81. data/lib/asciidoctor/pdf/section_info_by_page.rb +24 -0
  82. data/lib/asciidoctor/pdf/theme_loader.rb +89 -79
  83. data/lib/asciidoctor/pdf/version.rb +1 -2
  84. data/lib/asciidoctor/pdf.rb +5 -2
  85. metadata +34 -64
  86. data/data/fonts/mplus1mn-bold-ascii.ttf +0 -0
  87. data/data/fonts/mplus1mn-bold_italic-ascii.ttf +0 -0
  88. data/data/fonts/mplus1mn-italic-ascii.ttf +0 -0
  89. data/data/fonts/mplus1mn-regular-ascii-conums.ttf +0 -0
  90. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +0 -7
  91. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +0 -7
  92. data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +0 -18
  93. data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +0 -33
  94. data/lib/asciidoctor/pdf/ext/core/array.rb +0 -11
  95. data/lib/asciidoctor/pdf/ext/core/hash.rb +0 -7
  96. data/lib/asciidoctor/pdf/ext/core/regexp.rb +0 -5
  97. data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +0 -8
  98. data/lib/asciidoctor-pdf/converter.rb +0 -3
  99. data/lib/asciidoctor-pdf/version.rb +0 -3
@@ -1,5 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Asciidoctor::Document
4
- alias catalog references unless method_defined? :catalog
4
+ # promote preface block (i.e., preamble block with title in book doctype) to preface section
5
+ # FIXME: this should be handled by core
6
+ def promote_preface_block
7
+ if doctype == 'book' && (blk0 = blocks[0])&.context == :preamble && blk0.title? && !blk0.title.nil_or_empty? &&
8
+ blk0.blocks[0]&.style != 'abstract' && (blk1 = blocks[1])&.context == :section
9
+ preface = Asciidoctor::Section.new self, blk1.level, false, attributes: { 1 => 'preface', 'style' => 'preface' }
10
+ preface.special = true
11
+ preface.sectname = 'preface'
12
+ preface.title = blk0.instance_variable_get :@title
13
+ preface.id = preface.generate_id
14
+ preface.blocks.replace (blk0.blocks.map do |b|
15
+ b.parent = preface
16
+ b
17
+ end)
18
+ blocks[0] = preface
19
+ end
20
+ nil
21
+ end
5
22
  end
@@ -2,25 +2,19 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Image
5
- DataUriRx = /^data:image\/(?<fmt>png|jpe?g|gif|pdf|bmp|tiff|svg\+xml);base64,(?<data>.*)$/
5
+ DataUriRx = %r(^data:image/(?<fmt>png|jpe?g|gif|pdf|bmp|tiff|svg\+xml);base64,(?<data>.*)$)
6
6
  FormatAliases = { 'jpg' => 'jpeg', 'svg+xml' => 'svg' }
7
7
 
8
- class << self
9
- def format image_path, attributes = nil
10
- (attributes && attributes['format']) || ((ext = ::File.extname image_path).downcase.slice 1, ext.length)
11
- end
12
-
13
- def target_and_format image_path, attributes = nil
14
- if (image_path.start_with? 'data:') && (m = DataUriRx.match image_path)
15
- [(m[:data].extend ::Base64), (FormatAliases.fetch m[:fmt], m[:fmt])]
16
- else
17
- [image_path, (attributes && attributes['format']) || ((ext = ::File.extname image_path).downcase.slice 1, ext.length)]
18
- end
19
- end
8
+ def self.format image_path
9
+ ((ext = ::File.extname image_path).downcase.slice 1, ext.length)
20
10
  end
21
11
 
22
- def format
23
- (attr 'format', nil, false) || ((ext = ::File.extname(inline? ? target : (attr 'target'))).downcase.slice 1, ext.length)
12
+ def self.target_and_format image_path, attributes = nil
13
+ if (image_path.start_with? 'data:') && (m = DataUriRx.match image_path)
14
+ [(m[:data].extend ::Base64), (FormatAliases.fetch m[:fmt], m[:fmt])]
15
+ else
16
+ [image_path, attributes&.[]('format') || ((ext = ::File.extname image_path).downcase.slice 1, ext.length)]
17
+ end
24
18
  end
25
19
 
26
20
  def target_and_format
@@ -2,13 +2,6 @@
2
2
 
3
3
  # TODO: add these methods to Asciidoctor core
4
4
  class Asciidoctor::List
5
- # Check whether this list is an outline list (unordered or ordered).
6
- #
7
- # Return true if this list is an outline list. Otherwise, return false.
8
- def outline?
9
- @context == :ulist || @context == :olist
10
- end unless method_defined? :outline?
11
-
12
5
  # Check whether this list is nested inside the item of another list.
13
6
  #
14
7
  # Return true if the parent of this list is a list item. Otherwise, return false.
@@ -16,19 +9,19 @@ class Asciidoctor::List
16
9
  Asciidoctor::ListItem === @parent
17
10
  end unless method_defined? :nested?
18
11
 
19
- # Get the level of this list within the broader outline list (unordered or ordered) structure.
12
+ # Get the nesting level of this list within the broader list (unordered or ordered) structure.
20
13
  #
21
- # This method differs from the level property in that it considers all outline list ancestors.
14
+ # This method differs from the level property in that it considers only list ancestors.
22
15
  # It's important for selecting the marker for an unordered list.
23
16
  #
24
- # Return the 1-based level of this list within the outline list structure.
25
- def outline_level
17
+ # Return the 1-based level of this list within the list structure.
18
+ def list_level
26
19
  l = 1
27
20
  ancestor = self
28
21
  # FIXME: does not cross out of AsciiDoc table cell
29
22
  while (ancestor = ancestor.parent)
30
- l += 1 if Asciidoctor::List === ancestor && ancestor.outline?
23
+ l += 1 if Asciidoctor::List === ancestor && (ancestor.context == :ulist || ancestor.context == :olist)
31
24
  end
32
25
  l
33
- end unless method_defined? :outline_level
26
+ end unless method_defined? :list_level
34
27
  end
@@ -4,8 +4,7 @@ class Asciidoctor::Section
4
4
  def numbered_title opts = {}
5
5
  @cached_numbered_title ||= nil
6
6
  unless @cached_numbered_title
7
- slevel = @level == 0 && @special ? 1 : @level
8
- if @numbered && !@caption && slevel <= (@document.attr 'sectnumlevels', 3).to_i
7
+ if @numbered && !@caption && (slevel = @level) <= (@document.attr 'sectnumlevels', 3).to_i
9
8
  @is_numbered = true
10
9
  if @document.doctype == 'book'
11
10
  case slevel
@@ -14,14 +13,14 @@ class Asciidoctor::Section
14
13
  @cached_formal_numbered_title = %(#{@document.attr 'part-signifier', 'Part'} #{@cached_numbered_title}).lstrip
15
14
  when 1
16
15
  @cached_numbered_title = %(#{sectnum} #{title})
17
- @cached_formal_numbered_title = %(#{@document.attr 'chapter-signifier', (@document.attr 'chapter-label', 'Chapter')} #{@cached_numbered_title}).lstrip
16
+ @cached_formal_numbered_title = %(#{@document.attr 'chapter-signifier', 'Chapter'} #{@cached_numbered_title}).lstrip
18
17
  else
19
18
  @cached_formal_numbered_title = @cached_numbered_title = %(#{sectnum} #{title})
20
19
  end
21
20
  else
22
21
  @cached_formal_numbered_title = @cached_numbered_title = %(#{sectnum} #{title})
23
22
  end
24
- elsif slevel == 0
23
+ elsif @level == 0
25
24
  @is_numbered = false
26
25
  @cached_numbered_title = @cached_formal_numbered_title = title
27
26
  else
@@ -31,16 +30,4 @@ class Asciidoctor::Section
31
30
  end
32
31
  opts[:formal] ? @cached_formal_numbered_title : @cached_numbered_title
33
32
  end unless method_defined? :numbered_title
34
-
35
- def part?
36
- @document.doctype == 'book' && @level == 0 && !@special
37
- end unless method_defined? :part?
38
-
39
- def chapter?
40
- @document.doctype == 'book' && (@level == 1 || (@special && @level == 0))
41
- end unless method_defined? :chapter?
42
-
43
- def part_or_chapter?
44
- @document.doctype == 'book' && @level < 2
45
- end unless method_defined? :part_or_chapter?
46
33
  end
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # NOTE these are either candidates for inclusion in Asciidoctor core or backports
4
- require_relative 'asciidoctor/logging_shim' unless defined? Asciidoctor::Logging
5
- require_relative 'asciidoctor/abstract_node'
6
- require_relative 'asciidoctor/abstract_block'
3
+ # NOTE: these are either candidates for inclusion in Asciidoctor core or backports
7
4
  require_relative 'asciidoctor/document'
8
5
  require_relative 'asciidoctor/section'
9
6
  require_relative 'asciidoctor/list'
10
- require_relative 'asciidoctor/list_item'
11
7
  require_relative 'asciidoctor/image'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class File
4
- # NOTE: remove once minimum required Ruby version is at least 2.7
4
+ # NOTE: remove once minimum JRuby version is fully 2.7 compliant
5
5
  def self.absolute_path? path
6
6
  (::Pathname.new path).absolute?
7
7
  end unless respond_to? :absolute_path?
@@ -21,8 +21,5 @@ class QuantifiableStdout < SimpleDelegator
21
21
  super
22
22
  end
23
23
 
24
- def write content
25
- @size += content.to_s.bytesize
26
- super
27
- end
24
+ alias write <<
28
25
  end
@@ -3,11 +3,11 @@
3
3
  class String
4
4
  def pred
5
5
  # integers
6
- ((Integer self) - 1).to_s
6
+ (Integer self).pred.to_s
7
7
  rescue ::ArgumentError
8
8
  # chars (upper alpha, lower alpha, lower greek)
9
9
  ([65, 97, 945].include? ord) ? '0' : ([ord - 1].pack 'U1')
10
- end unless method_defined? :pred
10
+ end
11
11
 
12
12
  # If the string is ASCII only, convert it to a PDF LiteralString object. Otherwise, return self.
13
13
  def as_pdf
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'core/object'
4
- require_relative 'core/array'
5
3
  require_relative 'core/file'
6
- require_relative 'core/hash'
4
+ require_relative 'core/object'
7
5
  require_relative 'core/string'
8
- require_relative 'core/regexp'
9
6
  require_relative 'core/quantifiable_stdout'
@@ -3,31 +3,6 @@
3
3
  class PDF::Core::Page
4
4
  InitialPageContent = %(q\n)
5
5
 
6
- # Restore the new_content_stream method from PDF::Core::Page
7
- #
8
- # The prawn-templates gem relies on the new_content_stream method on
9
- # PDF::Core::Page, which was removed in pdf-core 0.3.1. prawn-templates is
10
- # used for importing a single-page PDF into the current document.
11
- #
12
- # see https://github.com/prawnpdf/pdf-core/commit/67f9a08a03bcfcc5a24cf76b135c218d3d3ab05d
13
- def new_content_stream
14
- return if in_stamp_stream?
15
- dictionary.data[:Contents] = [content] unless Array === dictionary.data[:Contents]
16
- @content = document.ref({})
17
- dictionary.data[:Contents] << document.state.store[@content]
18
- document.open_graphics_state
19
- end unless method_defined? :new_content_stream
20
-
21
- # NOTE alias method to avoid warning if another gem replaces this method
22
- alias __new_content_stream new_content_stream
23
-
24
- # Restore the imported_page? method from PDF::Core::Page
25
- #
26
- # see https://github.com/prawnpdf/pdf-core/commit/0e326a838e142061be8e062168190fae6b3b1dcf
27
- def imported_page?
28
- @imported_page
29
- end unless method_defined? :imported_page?
30
-
31
6
  # Record the page's current state as the tare content stream (i.e., empty, meaning no content has been written).
32
7
  def tare_content_stream
33
8
  @tare_content_stream = content.stream.filtered_stream
@@ -42,13 +17,13 @@ class PDF::Core::Page
42
17
  # Reset the content of the page.
43
18
  # Note that this method may leave behind an orphaned background image.
44
19
  def reset_content
45
- unless content.stream.filtered_stream == InitialPageContent
46
- xobjects.clear
47
- ext_gstates.clear
48
- new_content = document.state.store[document.ref({})]
49
- new_content << 'q' << ?\n
50
- content.replace new_content
51
- @tare_content_stream = InitialPageContent
52
- end
20
+ return if content.stream.filtered_stream == InitialPageContent
21
+ xobjects.clear
22
+ ext_gstates.clear
23
+ new_content = document.state.store[document.ref({})]
24
+ new_content << 'q' << ?\n
25
+ content.replace new_content
26
+ @tare_content_stream = InitialPageContent
27
+ nil
53
28
  end
54
29
  end
@@ -1,21 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module PDF::Core
4
- class << self
5
- alias _initial_real real
6
-
7
- # NOTE Makes v1.6.x work with the modified precision settings (0.5f) in Prawn 2.4 while preserving existing behavior
8
- def real num, precision = 4
9
- ("%.#{precision}f" % num).sub(/((?<!\.)0)+\z/, '')
10
- end
11
-
12
- alias _initial_real_params real_params
13
- def real_params array
14
- return array.map {|e| real e, 5 }.join(' ') if (caller_locations 1, 1)[0].base_label == 'transformation_matrix'
15
- _initial_real_params array
16
- end
17
- end
18
- end
19
-
20
- require_relative 'pdf-core/pdf_object'
21
3
  require_relative 'pdf-core/page'
@@ -14,8 +14,6 @@
14
14
  #
15
15
  ######################################################################
16
16
 
17
- require 'coderay'
18
-
19
17
  # Registers a to_prawn method with CodeRay. The method returns an array of hashes to be
20
18
  # used with Prawn::Text.formatted_text(array).
21
19
  #
@@ -71,7 +69,7 @@ module Asciidoctor
71
69
  super
72
70
  @out = []
73
71
  @open = []
74
- # NOTE tracks whether text token begins at the start of a line
72
+ # NOTE: tracks whether text token begins at the start of a line
75
73
  @start_of_line = true
76
74
  end
77
75
 
@@ -79,17 +77,17 @@ module Asciidoctor
79
77
  if text == LF
80
78
  @out << { text: text }
81
79
  @start_of_line = true
82
- # NOTE text is nil and kind is :error when CodeRay ends parsing on an error
80
+ # NOTE: text is nil and kind is :error when CodeRay ends parsing on an error
83
81
  elsif text
84
- # NOTE add guard character to prevent Prawn from trimming indentation
82
+ # NOTE: add guard character to prevent Prawn from trimming indentation
85
83
  text[0] = GuardedIndent if @start_of_line && (text.start_with? ' ')
86
84
  text.gsub! InnerIndent, GuardedInnerIndent if text.include? InnerIndent
87
85
 
88
- # NOTE this optimization assumes we don't support/use background colors
86
+ # NOTE: this optimization assumes we don't support/use background colors
89
87
  if text.rstrip.empty?
90
88
  @out << { text: text }
91
89
  else
92
- # QUESTION should we default to no color?
90
+ # QUESTION: should we default to no color?
93
91
  @out << { text: text, color: (COLORS[kind] || COLORS[@open[-1]] || COLORS[:default]) }
94
92
  end
95
93
  @start_of_line = text.end_with? LF