asciidoctor-pdf 1.6.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/.yardopts +1 -1
- data/CHANGELOG.adoc +273 -31
- data/NOTICE.adoc +16 -4
- data/README.adoc +208 -68
- data/asciidoctor-pdf.gemspec +3 -7
- data/data/fonts/ABOUT-mplus1mn-subset +1 -1
- data/data/fonts/ABOUT-mplus1p-subset +2 -2
- data/data/fonts/ABOUT-notosans-subset +26 -0
- data/data/fonts/ABOUT-notoserif-subset +1 -1
- data/data/fonts/{LICENSE-notoserif → LICENSE-noto} +0 -0
- data/data/fonts/mplus1mn-bold-subset.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-regular-subset.ttf +0 -0
- data/data/fonts/mplus1p-regular-fallback.ttf +0 -0
- data/data/fonts/notoemoji-subset.ttf +0 -0
- data/data/fonts/notosans-bold-subset.ttf +0 -0
- data/data/fonts/notosans-bold_italic-subset.ttf +0 -0
- data/data/fonts/notosans-italic-subset.ttf +0 -0
- data/data/fonts/notosans-regular-subset.ttf +0 -0
- data/data/fonts/notoserif-bold-subset.ttf +0 -0
- data/data/fonts/notoserif-bold_italic-subset.ttf +0 -0
- data/data/fonts/notoserif-italic-subset.ttf +0 -0
- data/data/fonts/notoserif-regular-subset.ttf +0 -0
- data/data/themes/base-theme.yml +21 -24
- data/data/themes/default-for-print-theme.yml +24 -0
- data/data/themes/default-for-print-with-fallback-font-theme.yml +3 -0
- data/data/themes/default-theme.yml +55 -59
- data/data/themes/default-with-fallback-font-theme.yml +2 -2
- data/data/themes/sans-with-fallback-font-theme.yml +10 -0
- data/docs/theming-guide.adoc +977 -352
- data/lib/asciidoctor/pdf/converter.rb +1853 -1566
- data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +22 -1
- data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +9 -15
- data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +6 -13
- data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +3 -16
- data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -5
- data/lib/asciidoctor/pdf/ext/core/file.rb +1 -1
- data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +1 -4
- data/lib/asciidoctor/pdf/ext/core/string.rb +2 -2
- data/lib/asciidoctor/pdf/ext/core.rb +1 -4
- data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +8 -33
- data/lib/asciidoctor/pdf/ext/pdf-core.rb +0 -16
- data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +5 -7
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +489 -331
- data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +0 -4
- data/lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb +1 -1
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +33 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +25 -14
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +9 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb +13 -0
- data/lib/asciidoctor/pdf/ext/prawn/images.rb +20 -18
- data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb +6 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb +22 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb +13 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg.rb +5 -2
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +76 -20
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +39 -1
- data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +21 -15
- data/lib/asciidoctor/pdf/ext/prawn-table.rb +1 -1
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/ext/pygments.rb +2 -2
- data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +17 -20
- data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
- data/lib/asciidoctor/pdf/ext/rouge.rb +0 -1
- data/lib/asciidoctor/pdf/formatted_text/formatter.rb +2 -2
- data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +8 -10
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +69 -78
- data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +7 -10
- data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +2 -4
- data/lib/asciidoctor/pdf/formatted_text/parser.rb +53 -47
- data/lib/asciidoctor/pdf/formatted_text/parser.treetop +5 -7
- data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +14 -14
- data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +4 -7
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +122 -110
- data/lib/asciidoctor/pdf/formatted_text.rb +0 -1
- data/lib/asciidoctor/pdf/index_catalog.rb +7 -11
- data/lib/asciidoctor/pdf/nogmagick.rb +6 -0
- data/lib/asciidoctor/pdf/optimizer.rb +3 -5
- data/lib/asciidoctor/pdf/pdfmark.rb +16 -8
- data/lib/asciidoctor/pdf/roman_numeral.rb +4 -22
- data/lib/asciidoctor/pdf/sanitizer.rb +18 -13
- data/lib/asciidoctor/pdf/section_info_by_page.rb +24 -0
- data/lib/asciidoctor/pdf/theme_loader.rb +100 -80
- data/lib/asciidoctor/pdf/version.rb +1 -2
- data/lib/asciidoctor/pdf.rb +5 -2
- metadata +36 -64
- data/data/fonts/mplus1mn-bold-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-regular-ascii-conums.ttf +0 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +0 -7
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +0 -7
- data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +0 -18
- data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +0 -33
- data/lib/asciidoctor/pdf/ext/core/array.rb +0 -11
- data/lib/asciidoctor/pdf/ext/core/hash.rb +0 -7
- data/lib/asciidoctor/pdf/ext/core/regexp.rb +0 -5
- data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +0 -8
- data/lib/asciidoctor-pdf/converter.rb +0 -3
- data/lib/asciidoctor-pdf/version.rb +0 -3
@@ -1,5 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Asciidoctor::Document
|
4
|
-
|
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
|
+
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
|
18
|
+
preface.blocks.replace (blk0.blocks.map do |b|
|
19
|
+
b.parent = preface
|
20
|
+
b
|
21
|
+
end)
|
22
|
+
blocks[0] = preface
|
23
|
+
end
|
24
|
+
nil
|
25
|
+
end
|
5
26
|
end
|
@@ -2,25 +2,19 @@
|
|
2
2
|
|
3
3
|
module Asciidoctor
|
4
4
|
module Image
|
5
|
-
DataUriRx =
|
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
|
-
|
9
|
-
|
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
|
23
|
-
(
|
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
|
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
|
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
|
25
|
-
def
|
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.
|
23
|
+
l += 1 if Asciidoctor::List === ancestor && (ancestor.context == :ulist || ancestor.context == :olist)
|
31
24
|
end
|
32
25
|
l
|
33
|
-
end unless method_defined? :
|
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
|
-
|
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',
|
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
|
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
|
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?
|
@@ -3,11 +3,11 @@
|
|
3
3
|
class String
|
4
4
|
def pred
|
5
5
|
# integers
|
6
|
-
(
|
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
|
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/
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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,19 +1,3 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module PDF::Core
|
4
|
-
class << self
|
5
|
-
alias _initial_real real
|
6
|
-
def real num
|
7
|
-
num.to_f.round 4
|
8
|
-
end
|
9
|
-
|
10
|
-
alias _initial_real_params real_params
|
11
|
-
def real_params array
|
12
|
-
return array.map {|it| it.to_f.round 5 }.join ' ' if (caller_locations 1, 1)[0].base_label == 'transformation_matrix'
|
13
|
-
_initial_real_params array
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
require_relative 'pdf-core/pdf_object'
|
19
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
|