asciidoctor-pdf 1.5.2 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +68 -1
- data/{LICENSE.adoc → LICENSE} +3 -4
- data/NOTICE.adoc +4 -6
- data/README.adoc +139 -46
- data/asciidoctor-pdf.gemspec +11 -14
- data/bin/asciidoctor-pdf-optimize +1 -1
- data/docs/theming-guide.adoc +26 -22
- data/lib/asciidoctor/pdf/converter.rb +88 -78
- data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +3 -2
- data/lib/asciidoctor/pdf/ext/core/file.rb +4 -5
- data/lib/asciidoctor/pdf/ext/core.rb +0 -1
- data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +1 -1
- data/lib/asciidoctor/pdf/ext/pdf-core.rb +15 -0
- data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +4 -13
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +28 -2
- data/lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb +1 -1
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +15 -0
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +28 -7
- data/lib/asciidoctor/pdf/ext/prawn-svg.rb +0 -1
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/ext/pygments.rb +11 -9
- data/lib/asciidoctor/pdf/ext.rb +0 -1
- data/lib/asciidoctor/pdf/formatted_text/fragment_position_renderer.rb +5 -1
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +9 -2
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +6 -4
- data/lib/asciidoctor/pdf/index_catalog.rb +1 -1
- data/lib/asciidoctor/pdf/optimizer.rb +40 -12
- data/lib/asciidoctor/pdf/pdfmark.rb +1 -2
- data/lib/asciidoctor/pdf/text_transformer.rb +10 -71
- data/lib/asciidoctor/pdf/theme_loader.rb +1 -1
- data/lib/asciidoctor/pdf/version.rb +1 -1
- data/lib/asciidoctor/pdf.rb +3 -0
- metadata +21 -63
- data/lib/asciidoctor/pdf/ext/core/numeric.rb +0 -26
- data/lib/asciidoctor/pdf/ext/prawn-svg/interface.rb +0 -14
- data/lib/asciidoctor/pdf/ext/prawn-templates.rb +0 -7
data/asciidoctor-pdf.gemspec
CHANGED
@@ -14,10 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.homepage = 'https://asciidoctor.org/docs/asciidoctor-pdf'
|
15
15
|
s.license = 'MIT'
|
16
16
|
# NOTE required ruby version is informational only; it's not enforced since it can't be overridden and can cause builds to break
|
17
|
-
#s.required_ruby_version = '>= 2.
|
17
|
+
#s.required_ruby_version = '>= 2.5.0'
|
18
18
|
s.metadata = {
|
19
19
|
'bug_tracker_uri' => 'https://github.com/asciidoctor/asciidoctor-pdf/issues',
|
20
|
-
'changelog_uri' => 'https://github.com/asciidoctor/asciidoctor-pdf/blob/
|
20
|
+
'changelog_uri' => 'https://github.com/asciidoctor/asciidoctor-pdf/blob/main/CHANGELOG.adoc',
|
21
21
|
'mailing_list_uri' => 'http://discuss.asciidoctor.org',
|
22
22
|
'source_code_uri' => 'https://github.com/asciidoctor/asciidoctor-pdf'
|
23
23
|
}
|
@@ -28,30 +28,27 @@ Gem::Specification.new do |s|
|
|
28
28
|
rescue
|
29
29
|
files = Dir['**/*']
|
30
30
|
end
|
31
|
-
s.files = files.grep %r/^(?:(?:data|lib)\/.+|docs\/theming-guide\.adoc|(?:CHANGELOG|
|
31
|
+
s.files = files.grep %r/^(?:(?:data|lib)\/.+|docs\/theming-guide\.adoc|LICENSE|(?:CHANGELOG|NOTICE|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$/
|
32
32
|
s.executables = (files.grep %r/^bin\//).map {|f| File.basename f }
|
33
33
|
s.require_paths = ['lib']
|
34
34
|
#s.test_files = files.grep %r/^(?:test|spec|feature)\/.*$/
|
35
35
|
|
36
|
-
s.add_runtime_dependency 'asciidoctor', '
|
37
|
-
s.add_runtime_dependency 'prawn', '~> 2.
|
38
|
-
# NOTE
|
39
|
-
s.add_runtime_dependency 'ttfunk', ['~> 1.5.0'], ['>= 1.5.1']
|
40
|
-
# NOTE must use prawn-table from master branch (defined in Gemfile) for full functionality
|
36
|
+
s.add_runtime_dependency 'asciidoctor', '~> 2.0'
|
37
|
+
s.add_runtime_dependency 'prawn', '~> 2.4.0'
|
38
|
+
# NOTE must use prawn-table from head (defined in Gemfile) for full functionality
|
41
39
|
s.add_runtime_dependency 'prawn-table', '~> 0.2.0'
|
42
40
|
s.add_runtime_dependency 'prawn-templates', '~> 0.1.0'
|
43
|
-
s.add_runtime_dependency 'prawn-svg', '~> 0.
|
44
|
-
s.add_runtime_dependency 'prawn-icon', '~>
|
41
|
+
s.add_runtime_dependency 'prawn-svg', '~> 0.32.0'
|
42
|
+
s.add_runtime_dependency 'prawn-icon', '~> 3.0.0'
|
45
43
|
s.add_runtime_dependency 'safe_yaml', '~> 1.0.0'
|
46
|
-
s.add_runtime_dependency '
|
47
|
-
s.add_runtime_dependency 'concurrent-ruby', '~> 1.1.0'
|
44
|
+
s.add_runtime_dependency 'concurrent-ruby', '~> 1.1'
|
48
45
|
s.add_runtime_dependency 'treetop', '~> 1.6.0'
|
49
46
|
|
50
47
|
s.add_development_dependency 'rake', '~> 13.0.0'
|
51
|
-
s.add_development_dependency 'rspec', '~> 3.
|
48
|
+
s.add_development_dependency 'rspec', '~> 3.10.0'
|
52
49
|
s.add_development_dependency 'pdf-inspector', '~> 1.3.0'
|
53
50
|
# Asciidoctor PDF supports Rouge >= 2 (verified in CI build using 2.0.0)
|
54
51
|
s.add_development_dependency 'rouge', '~> 3.0'
|
55
52
|
s.add_development_dependency 'coderay', '~> 1.1.0'
|
56
|
-
s.add_development_dependency 'chunky_png', '~> 1.
|
53
|
+
s.add_development_dependency 'chunky_png', '~> 1.4.0'
|
57
54
|
end
|
data/docs/theming-guide.adoc
CHANGED
@@ -141,7 +141,7 @@ Otherwise, Asciidoctor PDF will use built-in AFM fonts, which can result in miss
|
|
141
141
|
|
142
142
|
[TIP]
|
143
143
|
====
|
144
|
-
Instead of creating a theme from scratch, another option is to download the https://github.com/asciidoctor/asciidoctor-pdf/blob/
|
144
|
+
Instead of creating a theme from scratch, another option is to download the https://github.com/asciidoctor/asciidoctor-pdf/blob/main/data/themes/default-theme.yml[default-theme.yml] file from the source repository.
|
145
145
|
Save the file using a unique name (e.g., _custom-theme.yml_) and start hacking on it.
|
146
146
|
|
147
147
|
Alternatively, you can snag the file from your local installation using the following command:
|
@@ -752,8 +752,9 @@ A sans-serif font that provides a very complete set of Unicode glyphs.
|
|
752
752
|
Cannot be styled as italic, bold or bold_italic.
|
753
753
|
Used as the fallback font in the `default-with-fallback-font` theme.
|
754
754
|
|
755
|
-
TIP:
|
756
|
-
|
755
|
+
TIP: The default themes in 1.5.x do not include the `GEM_FONTS_DIR` prefix in the path of the bundled font files.
|
756
|
+
Therefore, if you want to specify the location of custom fonts using the `pdf-fontsdir` attribute, yet still be able to use the bundled fonts, you need to refer to the bundled fonts using the `GEM_FONTS_DIR` token.
|
757
|
+
To do so, you can either a) redeclare the bundle fonts in your theme and prefix the path with the segment `GEM_FONTS_DIR` (e.g., `GEM_FONTS_DIR/mplus1p-regular-fallback.ttf`, or b) include `GEM_FONT_DIR` in the value of the `pdf-fontsdir` attribute separated by the location of your custom fonts using a semi-colon (e.g., `"path/to/your/fonts;GEM_FONTS_DIR"`).
|
757
758
|
|
758
759
|
=== Custom Fonts
|
759
760
|
|
@@ -963,9 +964,9 @@ This nested structure is for organizational purposes only.
|
|
963
964
|
All keys are flatted when the theme is loaded (e.g., `align` nested under `base` becomes `base-align`).
|
964
965
|
|
965
966
|
The converter uses the values of these keys to control how most elements are arranged and styled in the PDF.
|
966
|
-
The default values listed in this section get inherited from the https://github.com/asciidoctor/asciidoctor-pdf/blob/
|
967
|
+
The default values listed in this section get inherited from the https://github.com/asciidoctor/asciidoctor-pdf/blob/main/data/themes/base-theme.yml[base theme].
|
967
968
|
|
968
|
-
IMPORTANT: The https://github.com/asciidoctor/asciidoctor-pdf/blob/
|
969
|
+
IMPORTANT: The https://github.com/asciidoctor/asciidoctor-pdf/blob/main/data/themes/default-theme.yml[default theme] has a different set of values which are not shown in this guide.
|
969
970
|
|
970
971
|
When creating a theme, all keys are optional.
|
971
972
|
Required keys are provided by the base theme.
|
@@ -1256,7 +1257,8 @@ To disable the image, use the value `none`.
|
|
1256
1257
|
These margins and used when the value `prepress` is assigned to the `media` document attribute.
|
1257
1258
|
If no cover is specified, the recto margin is not applied to the title page.
|
1258
1259
|
To apply the recto margin to the title page, but not include a cover, assign the value `~` to the `front-cover-image` attribute.
|
1259
|
-
.
|
1260
|
+
. Only works if the document uses a title page (i.e., doctype is book or `title-page` attribute is set)
|
1261
|
+
The `toc` value only applies if the toc is in the default location (before the first page of the body).
|
1260
1262
|
If the toc macro is used to position the toc, the start-at behavior is the same as if the toc is not enabled.
|
1261
1263
|
If value is an integer, page numbering will start at the specified page of the body (i.e., 1 is first page, 2 is second page, etc.)
|
1262
1264
|
|
@@ -3363,7 +3365,7 @@ The keys in this category control the arrangement of block images.
|
|
3363
3365
|
|font-style
|
3364
3366
|
|<<font-styles,Font style>> +
|
3365
3367
|
(default: normal)
|
3366
|
-
|
|
3368
|
+
|image:
|
3367
3369
|
alt:
|
3368
3370
|
font-style: italic
|
3369
3371
|
|
@@ -3382,8 +3384,9 @@ The keys in this category control the arrangement of block images.
|
|
3382
3384
|
max-width: fit-content
|
3383
3385
|
|===
|
3384
3386
|
|
3385
|
-
. Only applies to block images.
|
3386
|
-
If specified, this value takes precedence over the value of the `width` attribute on the image macro, but not over the value of the `pdfwidth`
|
3387
|
+
. Only applies to block images that don't have either a `pdfwidth` or `scaledwidth` attribute on the image macro.
|
3388
|
+
If specified, this value takes precedence over the value of the `width` attribute on the image macro, but not over the value of the `pdfwidth` or `scaledwidth` attributes.
|
3389
|
+
This key accepts the same values as the `pdfwidth` attribute.
|
3387
3390
|
. The border is only used if a border color is specified, the border width is specified, the border width is greater than 0, and the `noborder` role is not present.
|
3388
3391
|
The border is drawn above the image on the inside of the box reserved for the image.
|
3389
3392
|
. The value `auto` means the border should expand to fit the width of the container (i.e., full width) instead of the image.
|
@@ -3639,8 +3642,8 @@ The subject stop can be customized using the `subject-stop` attribute.
|
|
3639
3642
|
[source,asciidoc]
|
3640
3643
|
----
|
3641
3644
|
[unordered]
|
3642
|
-
|
3643
|
-
|
3645
|
+
alpha:: partially complete and unstable
|
3646
|
+
beta:: feature complete and undergoing testing
|
3644
3647
|
----
|
3645
3648
|
====
|
3646
3649
|
|
@@ -4135,7 +4138,7 @@ Since Asciidoctor 2, table stripes are not enabled by default (e.g., `stripes=no
|
|
4135
4138
|
[#keys-footnotes]
|
4136
4139
|
=== Footnotes
|
4137
4140
|
|
4138
|
-
The keys in this
|
4141
|
+
The keys in this category control the style of the footnotes list at the end of the chapter (book) or document (otherwise).
|
4139
4142
|
If the `footnotes-title` attribute is specified, it is styled as a block caption.
|
4140
4143
|
The styling of the links is controlled by the global link styles.
|
4141
4144
|
|
@@ -4678,7 +4681,8 @@ To avoid this problem, reduce the height of the running content periphery or mak
|
|
4678
4681
|
The `columns` key can also be defined one level up (on `header` or `footer`), in which case the setting will be inherited.
|
4679
4682
|
Where the page sides fall in relation to the physical or printed page number is controlled using the `pdf-folio-placement` attribute (except when `media=prepress`, which implies `physical`).
|
4680
4683
|
. `<position>` can be `left`, `center` or `right`.
|
4681
|
-
.
|
4684
|
+
. Only works if the document uses a title page (i.e., doctype is book or `title-page` attribute is set)
|
4685
|
+
The `toc` value only applies if the toc is in the default location (before the first page of the body).
|
4682
4686
|
If the toc macro is used to position the toc, the start-at behavior is the same as if the toc is not enabled.
|
4683
4687
|
If value is an integer, the running content will start at the specified page of the body (i.e., 1 is first page, 2 is second page, etc.)
|
4684
4688
|
|
@@ -4741,7 +4745,7 @@ footer:
|
|
4741
4745
|
----
|
4742
4746
|
|
4743
4747
|
The `&shared_footer` assigns an ID to the YAML subtree under the `recto` key and the `*shared_footer` outputs a copy of it under the `verso` key.
|
4744
|
-
This technique can be used
|
4748
|
+
This technique can be used throughout the theme file as it's a core feature of YAML.
|
4745
4749
|
|
4746
4750
|
==== Attribute References
|
4747
4751
|
|
@@ -4762,7 +4766,7 @@ This feature allows you to have alternate lines that are selected when all the a
|
|
4762
4766
|
One case where this is useful is when referencing the `page-number` attribute.
|
4763
4767
|
If you unset the `pagenums` attribute on the document, any line in the running content that makes reference to `\{page-number}` will be dropped.
|
4764
4768
|
|
4765
|
-
You can also built-in AsciiDoc text replacements like `+(C)+`, numeric character references like `+©+`,
|
4769
|
+
You can also use built-in AsciiDoc text replacements like `+(C)+`, numeric character references like `+©+`, hexadecimal character references like `+€+`, and inline formatting (e.g., bold, italic, monospace).
|
4766
4770
|
|
4767
4771
|
Here's an example that shows how attributes and replacements can be used in the running footer:
|
4768
4772
|
|
@@ -4836,7 +4840,7 @@ header:
|
|
4836
4840
|
center:
|
4837
4841
|
content: $header-recto-center-content
|
4838
4842
|
----
|
4839
|
-
<1> You can use the `image-vertical-align` key to
|
4843
|
+
<1> You can use the `image-vertical-align` key to slightly nudge the image up or down.
|
4840
4844
|
|
4841
4845
|
CAUTION: By default, the image must fit in the allotted space for the running header or footer.
|
4842
4846
|
Otherwise, you will run into layout issues.
|
@@ -5159,7 +5163,7 @@ Each style declaration accepts the following properties:
|
|
5159
5163
|
* `inline_block` - fill the background color to the height of the line (Asciidoctor PDF only)
|
5160
5164
|
* `extend` - extend the background color to the end of the line for a line-oriented match (Asciidoctor PDF only)
|
5161
5165
|
|
5162
|
-
Colors are defined using
|
5166
|
+
Colors are defined using hexadecimal format (e.g., #ff0000 for red).
|
5163
5167
|
|
5164
5168
|
Use the `Text` token to set the background color of the source block and the default text color.
|
5165
5169
|
|
@@ -5219,7 +5223,7 @@ When you override an inline element, you return pseudo-HTML, which is then parse
|
|
5219
5223
|
|
5220
5224
|
The pseudo-HTML in Asciidoctor PDF evolved from the inline formatting in Prawn, now supporting the following elements: a, br, button, code, color, del, em, font, img, key, mark, span, strong, sub, sup.
|
5221
5225
|
All decimal and hexadecimal character references are supported, as well as the named entities amp, apos, gt, lt, nbsp, and quot (e.g., `\'`).
|
5222
|
-
You can change the font color using `rgb`
|
5226
|
+
You can change the font color using the `rgb` attribute on the `color` element (e.g., `<color rgb="#ff0000">`) and the font family and size using the `name` and `size` attributes on the `font` element, respectively (e.g., `<font name="sans" size="12">`).
|
5223
5227
|
You can also use the `style` attribute on `span` to control the font color, weight, and style using the relevant CSS property names.
|
5224
5228
|
The pseudo-HTML in Asciidoctor PDF also supports the `class` attribute on any element for applying roles from the theme.
|
5225
5229
|
(Though not recommended, you can pass this pseudo-HTML straight through to Prawn using an inline passthrough in AsciiDoc).
|
@@ -5239,7 +5243,7 @@ end
|
|
5239
5243
|
----
|
5240
5244
|
|
5241
5245
|
As it stands, the converter doesn't do anything differently than the primary converter because we haven't yet overridden any of its methods.
|
5242
|
-
Let's do that now, starting by overriding the thematic break (aka
|
5246
|
+
Let's do that now, starting by overriding the thematic break (aka horizontal rule) to make it render like a ribbon:
|
5243
5247
|
|
5244
5248
|
[source,ruby]
|
5245
5249
|
----
|
@@ -5405,12 +5409,12 @@ You may need to scale the glyph so it fits properly in the art box.
|
|
5405
5409
|
IMPORTANT: If you're copying a non-visible character, be sure to set the width to 0 using menu:Metrics[Set Width...], enter 0 into *Set Width To*, then click btn:[OK].
|
5406
5410
|
|
5407
5411
|
When you're done, save the font with the old-style kern table enabled.
|
5408
|
-
To do so, select menu:File[Generate Fonts...], click btn:[Options],
|
5412
|
+
To do so, select menu:File[Generate Fonts...], select *TrueType*, click btn:[Options], make sure _only_ the following options are checked (equivalent to the flags 0x90 + 0x08):
|
5409
5413
|
|
5410
5414
|
* [x] OpenType
|
5411
5415
|
** [x] Old style 'kern'
|
5412
5416
|
|
5413
|
-
Then click btn:[Generate] to generate and save the font.
|
5417
|
+
Then click btn:[OK], then uncheck *Validate Before Saving*, and finally click btn:[Generate] to generate and save the font.
|
5414
5418
|
|
5415
5419
|
Your font file is now ready to be used with Asciidoctor PDF.
|
5416
5420
|
|
@@ -5420,5 +5424,5 @@ Performing all this font modification manually can be tedious (not to mention ha
|
|
5420
5424
|
Fortunately, FontForge provides a {url-fontforge-scripting}[scripting interface], which you can use to automate the process.
|
5421
5425
|
|
5422
5426
|
In fact, that's what we use to prepare the fonts that are bundled with Asciidoctor PDF.
|
5423
|
-
You can find that FontForge script, the Bash script that calls it, and the Docker image in which it is run in the https://github.com/asciidoctor/asciidoctor-pdf/tree/
|
5427
|
+
You can find that FontForge script, the Bash script that calls it, and the Docker image in which it is run in the https://github.com/asciidoctor/asciidoctor-pdf/tree/main/scripts[scripts directory] of this project.
|
5424
5428
|
You can use that script as a starting point or reference for your own font preparation / modification script.
|
@@ -32,7 +32,7 @@ module Asciidoctor
|
|
32
32
|
PygmentsRequirePath = ::File.join __dir__, 'ext/pygments'
|
33
33
|
OptimizerRequirePath = ::File.join __dir__, 'optimizer'
|
34
34
|
|
35
|
-
AsciidoctorVersion = ::Gem::Version.
|
35
|
+
AsciidoctorVersion = ::Gem::Version.new ::Asciidoctor::VERSION
|
36
36
|
AdmonitionIcons = {
|
37
37
|
caution: { name: 'fas-fire', stroke_color: 'BF3400', size: 24 },
|
38
38
|
important: { name: 'fas-exclamation-circle', stroke_color: 'BF0000', size: 24 },
|
@@ -92,7 +92,7 @@ module Asciidoctor
|
|
92
92
|
'circled' => (?\u2460..?\u2473).to_a,
|
93
93
|
'filled' => (?\u2776..?\u277f).to_a + (?\u24eb..?\u24f4).to_a,
|
94
94
|
}
|
95
|
-
SimpleAttributeRefRx = /(?<!\\)\{\w+(
|
95
|
+
SimpleAttributeRefRx = /(?<!\\)\{\w+(?:-\w+)*\}/
|
96
96
|
MeasurementRxt = '\\d+(?:\\.\\d+)?(?:in|cm|mm|p[txc])?'
|
97
97
|
MeasurementPartsRx = /^(\d+(?:\.\d+)?)(in|mm|cm|p[txc])?$/
|
98
98
|
PageSizeRx = /^(?:\[(#{MeasurementRxt}), ?(#{MeasurementRxt})\]|(#{MeasurementRxt})(?: x |x)(#{MeasurementRxt})|\S+)$/
|
@@ -108,6 +108,7 @@ module Asciidoctor
|
|
108
108
|
WhitespaceChars = ' ' + TAB + LF
|
109
109
|
ValueSeparatorRx = /;|,/
|
110
110
|
HexColorRx = /^#[a-fA-F0-9]{6}$/
|
111
|
+
VimeoThumbnailRx = /<thumbnail_url>(.*?)<\/thumbnail_url>/
|
111
112
|
SourceHighlighters = %w(coderay pygments rouge).to_set
|
112
113
|
ViewportWidth = ::Module.new
|
113
114
|
(TitleStyles = {
|
@@ -125,10 +126,6 @@ module Asciidoctor
|
|
125
126
|
# NOTE enabling data-uri forces Asciidoctor Diagram to produce absolute image paths
|
126
127
|
doc.attributes['data-uri'] = ((doc.instance_variable_get :@attribute_overrides) || {})['data-uri'] = ''
|
127
128
|
end
|
128
|
-
@capabilities = {
|
129
|
-
special_sectnums: AsciidoctorVersion >= (::Gem::Version.create '1.5.7'),
|
130
|
-
syntax_highlighter: AsciidoctorVersion >= (::Gem::Version.create '2.0.0'),
|
131
|
-
}
|
132
129
|
@initial_instance_variables = [:@initial_instance_variables] + instance_variables
|
133
130
|
end
|
134
131
|
|
@@ -164,9 +161,6 @@ module Asciidoctor
|
|
164
161
|
init_pdf doc
|
165
162
|
# set default value for pagenums if not otherwise set
|
166
163
|
doc.attributes['pagenums'] = '' unless (doc.attribute_locked? 'pagenums') || ((doc.instance_variable_get :@attributes_modified).include? 'pagenums')
|
167
|
-
if (idx_sect = doc.sections.find {|candidate| candidate.sectname == 'index' }) && idx_sect.numbered
|
168
|
-
idx_sect.numbered = false
|
169
|
-
end unless @capabilities[:special_sectnums]
|
170
164
|
#assign_missing_section_ids doc
|
171
165
|
|
172
166
|
# promote anonymous preface (defined using preamble block) to preface section
|
@@ -333,7 +327,7 @@ module Asciidoctor
|
|
333
327
|
# QUESTION should ThemeLoader handle registering fonts instead?
|
334
328
|
register_fonts theme.font_catalog, (doc.attr 'pdf-fontsdir', 'GEM_FONTS_DIR')
|
335
329
|
default_kerning theme.base_font_kerning != 'none'
|
336
|
-
@fallback_fonts =
|
330
|
+
@fallback_fonts = Array theme.font_fallbacks
|
337
331
|
@allow_uri_read = doc.attr? 'allow-uri-read'
|
338
332
|
@cache_uri = doc.attr? 'cache-uri'
|
339
333
|
@tmp_files = {}
|
@@ -374,7 +368,10 @@ module Asciidoctor
|
|
374
368
|
@index = IndexCatalog.new
|
375
369
|
# NOTE: we have to init Pdfmark class here while we have reference to the doc
|
376
370
|
@pdfmark = (doc.attr? 'pdfmark') ? (Pdfmark.new doc) : nil
|
377
|
-
|
371
|
+
# NOTE: defer instantiating optimizer until we know min pdf version
|
372
|
+
if (@optimize = doc.attr 'optimize')
|
373
|
+
@optimize = nil unless (defined? ::Asciidoctor::PDF::Optimizer) || !(Helpers.require_library OptimizerRequirePath, 'rghost', :warn).nil?
|
374
|
+
end
|
378
375
|
init_scratch_prototype
|
379
376
|
self
|
380
377
|
end
|
@@ -571,9 +568,10 @@ module Asciidoctor
|
|
571
568
|
# NOTE: section must have pdf-anchor in order to be listed in the TOC
|
572
569
|
sect.set_attr 'pdf-anchor', (sect_anchor = derive_anchor_from_id sect.id, %(#{start_pgnum}-#{y.ceil}))
|
573
570
|
add_dest_for_block sect, sect_anchor
|
574
|
-
|
571
|
+
case type
|
572
|
+
when :part
|
575
573
|
layout_part_title sect, title, align: align, level: hlevel
|
576
|
-
|
574
|
+
when :chapter
|
577
575
|
layout_chapter_title sect, title, align: align, level: hlevel
|
578
576
|
else
|
579
577
|
layout_heading title, align: align, level: hlevel, outdent: true
|
@@ -609,13 +607,18 @@ module Asciidoctor
|
|
609
607
|
def layout_footnotes node
|
610
608
|
return if (fns = (doc = node.document).footnotes - @footnotes).empty?
|
611
609
|
theme_margin :footnotes, :top
|
612
|
-
|
613
|
-
(
|
614
|
-
|
615
|
-
|
616
|
-
|
610
|
+
with_dry_run do |box_height = nil|
|
611
|
+
if box_height && (delta = cursor - box_height) > 0
|
612
|
+
move_down delta
|
613
|
+
end
|
614
|
+
theme_font :footnotes do
|
615
|
+
(title = doc.attr 'footnotes-title') && (layout_caption title, category: :footnotes)
|
616
|
+
item_spacing = @theme.footnotes_item_spacing
|
617
|
+
fns.each do |fn|
|
618
|
+
layout_prose %(<a id="_footnotedef_#{index = fn.index}">#{DummyText}</a>[<a anchor="_footnoteref_#{index}">#{index}</a>] #{fn.text}), margin_bottom: item_spacing, hyphenate: true
|
619
|
+
end
|
620
|
+
@footnotes += fns unless scratch?
|
617
621
|
end
|
618
|
-
@footnotes += fns
|
619
622
|
end
|
620
623
|
nil
|
621
624
|
end
|
@@ -1077,7 +1080,7 @@ module Asciidoctor
|
|
1077
1080
|
stack_subject = node.has_role? 'stack'
|
1078
1081
|
subject_stop = node.attr 'subject-stop', (stack_subject ? nil : ':'), false
|
1079
1082
|
node.items.each do |subjects, dd|
|
1080
|
-
subject =
|
1083
|
+
subject = (Array subjects).first.text
|
1081
1084
|
list_item_text = %(+++<strong>#{subject}#{(StopPunctRx.match? sanitize subject) ? '' : subject_stop}</strong>#{dd.text? ? "#{stack_subject ? '<br>' : ' '}#{dd.text}" : ''}+++)
|
1082
1085
|
list_item = ListItem.new list, list_item_text
|
1083
1086
|
dd.blocks.each {|it| list_item << it }
|
@@ -1333,8 +1336,14 @@ module Asciidoctor
|
|
1333
1336
|
marker_gap = rendered_width_of_char 'x'
|
1334
1337
|
font marker_style[:font_family], size: marker_style[:font_size] do
|
1335
1338
|
marker_width = rendered_width_of_string marker
|
1339
|
+
# NOTE compensate if character_spacing is not applied to first character
|
1340
|
+
# see https://github.com/prawnpdf/prawn/commit/c61c5d48841910aa11b9e3d6f0e01b68ce435329
|
1341
|
+
character_spacing_correction = 0
|
1342
|
+
character_spacing(-0.5) do
|
1343
|
+
character_spacing_correction = 0.5 if (rendered_width_of_char 'x', character_spacing: -0.5) == marker_gap
|
1344
|
+
end
|
1336
1345
|
marker_height = height_of_typeset_text marker, line_height: marker_style[:line_height], single_line: true
|
1337
|
-
start_position = -marker_width + -marker_gap
|
1346
|
+
start_position = -marker_width + -marker_gap + character_spacing_correction
|
1338
1347
|
float do
|
1339
1348
|
start_new_page if @media == 'prepress' && cursor < marker_height
|
1340
1349
|
flow_bounding_box start_position, width: marker_width do
|
@@ -1527,7 +1536,7 @@ module Asciidoctor
|
|
1527
1536
|
layout_caption node, category: :image, side: :bottom, block_align: alignment, block_width: rendered_w, max_width: @theme.image_caption_max_width if node.title?
|
1528
1537
|
theme_margin :block, :bottom unless pinned
|
1529
1538
|
rescue
|
1530
|
-
on_image_error :exception, node, target, (opts.merge message: %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! ? '; install prawn-gmagick gem to add support' : ''}))
|
1539
|
+
on_image_error :exception, node, target, (opts.merge message: %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! && !(defined? ::GMagick::Image) ? '; install prawn-gmagick gem to add support' : ''}))
|
1531
1540
|
end
|
1532
1541
|
end
|
1533
1542
|
|
@@ -1591,14 +1600,9 @@ module Asciidoctor
|
|
1591
1600
|
when 'vimeo'
|
1592
1601
|
video_path = %(https://vimeo.com/#{video_id = node.attr 'target'})
|
1593
1602
|
if allow_uri_read
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
::OpenURI
|
1598
|
-
end
|
1599
|
-
poster = ::OpenURI.open_uri %(http://vimeo.com/api/v2/video/#{video_id}.xml), 'r' do |f|
|
1600
|
-
/<thumbnail_large>(.*?)<\/thumbnail_large>/ =~ f.read && $1
|
1601
|
-
end
|
1603
|
+
poster = load_open_uri.open_uri(%(https://vimeo.com/api/oembed.xml?url=https%3A//vimeo.com/#{video_id}&width=1280), 'r') {|f| (VimeoThumbnailRx.match f.read)[1] } rescue nil
|
1604
|
+
else
|
1605
|
+
poster = nil
|
1602
1606
|
end
|
1603
1607
|
type = 'Vimeo video'
|
1604
1608
|
else
|
@@ -1630,9 +1634,7 @@ module Asciidoctor
|
|
1630
1634
|
add_dest_for_block node if node.id
|
1631
1635
|
|
1632
1636
|
# HACK: disable built-in syntax highlighter; must be done before calling node.content!
|
1633
|
-
if node.style == 'source' && (highlighter =
|
1634
|
-
(syntax_hl = node.document.syntax_highlighter) && syntax_hl.highlight? && syntax_hl.name :
|
1635
|
-
(highlighter = node.document.attributes['source-highlighter']) && (SourceHighlighters.include? highlighter) && highlighter)
|
1637
|
+
if node.style == 'source' && (highlighter = (syntax_hl = node.document.syntax_highlighter)&.highlight? && syntax_hl.name)
|
1636
1638
|
case highlighter
|
1637
1639
|
when 'coderay'
|
1638
1640
|
unless defined? ::Asciidoctor::Prawn::CodeRayEncoder
|
@@ -1702,7 +1704,7 @@ module Asciidoctor
|
|
1702
1704
|
# NOTE: highlight can return nil if something goes wrong; fallback to encoded source string if this happens
|
1703
1705
|
result = (lexer.highlight source_string, options: lexer_opts) || (node.apply_subs source_string, [:specialcharacters])
|
1704
1706
|
if node.attr? 'highlight', nil, false
|
1705
|
-
if (highlight_lines = (node.method :resolve_lines_to_highlight).arity > 1 ?
|
1707
|
+
if (highlight_lines = (node.method :resolve_lines_to_highlight).arity.abs > 1 ?
|
1706
1708
|
(node.resolve_lines_to_highlight source_string, (node.attr 'highlight')) :
|
1707
1709
|
(node.resolve_lines_to_highlight node.attr 'highlight')).empty?
|
1708
1710
|
highlight_lines = nil
|
@@ -1750,7 +1752,7 @@ module Asciidoctor
|
|
1750
1752
|
lexer ||= ::Rouge::Lexers::PlainText
|
1751
1753
|
source_string, conum_mapping = extract_conums source_string
|
1752
1754
|
if node.attr? 'highlight', nil, false
|
1753
|
-
unless (hl_lines = (node.method :resolve_lines_to_highlight).arity > 1 ?
|
1755
|
+
unless (hl_lines = (node.method :resolve_lines_to_highlight).arity.abs > 1 ?
|
1754
1756
|
(node.resolve_lines_to_highlight source_string, (node.attr 'highlight')) :
|
1755
1757
|
(node.resolve_lines_to_highlight node.attr 'highlight')).empty?
|
1756
1758
|
formatter_opts[:highlight_lines] = hl_lines.map {|linenum| [linenum, true] }.to_h
|
@@ -1853,7 +1855,10 @@ module Asciidoctor
|
|
1853
1855
|
line << fragment
|
1854
1856
|
end
|
1855
1857
|
end
|
1856
|
-
|
1858
|
+
conum_font_color = @theme.conum_font_color
|
1859
|
+
if (conum_font_name = @theme.conum_font_family) == font_name
|
1860
|
+
conum_font_name = nil
|
1861
|
+
end
|
1857
1862
|
last_line_num = lines.size - 1
|
1858
1863
|
if linenums
|
1859
1864
|
pad_size = (last_line_num + 1).to_s.length
|
@@ -1870,7 +1875,10 @@ module Asciidoctor
|
|
1870
1875
|
if conum_mapping && (conums = conum_mapping.delete cur_line_num)
|
1871
1876
|
line << { text: conums.shift } if ::String === conums[0]
|
1872
1877
|
conum_text = conums.map {|num| conum_glyph num }.join ' '
|
1873
|
-
|
1878
|
+
conum_fragment = { text: conum_text }
|
1879
|
+
conum_fragment[:color] = conum_font_color if conum_font_color
|
1880
|
+
conum_fragment[:font] = conum_font_name if conum_font_name
|
1881
|
+
line << conum_fragment
|
1874
1882
|
end
|
1875
1883
|
line << { text: LF } unless last_line
|
1876
1884
|
line
|
@@ -2040,7 +2048,7 @@ module Asciidoctor
|
|
2040
2048
|
end
|
2041
2049
|
unless cell_data.key? :content
|
2042
2050
|
cell_text = cell.text.strip
|
2043
|
-
cell_text = transform_text cell_text if cell_transform
|
2051
|
+
cell_text = transform_text cell_text, cell_transform if cell_transform
|
2044
2052
|
cell_text = hyphenate_text cell_text, @hyphenator if defined? @hyphenator
|
2045
2053
|
cell_text = cell_text.gsub CjkLineBreakRx, ZeroWidthSpace if @cjk_line_breaks
|
2046
2054
|
if cell_text.include? LF
|
@@ -2115,10 +2123,6 @@ module Asciidoctor
|
|
2115
2123
|
else
|
2116
2124
|
table_width = bounds.width * ((node.attr 'tablepcwidth') / 100.0)
|
2117
2125
|
column_widths = node.columns.map {|col| ((col.attr 'colpcwidth') * table_width) / 100.0 }
|
2118
|
-
# NOTE: until Asciidoctor 1.5.4, colpcwidth values didn't always add up to 100%; use last column to compensate
|
2119
|
-
unless column_widths.empty? || (width_delta = table_width - column_widths.sum) == 0
|
2120
|
-
column_widths[-1] += width_delta
|
2121
|
-
end
|
2122
2126
|
end
|
2123
2127
|
|
2124
2128
|
if ((alignment = node.attr 'align', nil, false) && (BlockAlignmentNames.include? alignment)) ||
|
@@ -2349,7 +2353,7 @@ module Asciidoctor
|
|
2349
2353
|
bare_target = target
|
2350
2354
|
text = node.text
|
2351
2355
|
end
|
2352
|
-
if (role = node.attr 'role', nil, false) && (role == 'bare' || (
|
2356
|
+
if (role = node.attr 'role', nil, false) && (role == 'bare' || (role.split.include? 'bare'))
|
2353
2357
|
# QUESTION should we insert breakable chars into URI when building fragment instead?
|
2354
2358
|
%(<a href="#{target}"#{attrs.join}>#{breakable_uri text}</a>)
|
2355
2359
|
# NOTE @media may not be initialized if method is called before convert phase
|
@@ -2368,13 +2372,8 @@ module Asciidoctor
|
|
2368
2372
|
%(<a href="#{target}">#{node.text || path}</a>)
|
2369
2373
|
elsif (refid = node.attributes['refid'])
|
2370
2374
|
unless (text = node.text)
|
2371
|
-
if (
|
2372
|
-
|
2373
|
-
text = ref.xreftext node.attr 'xrefstyle', nil, true
|
2374
|
-
end
|
2375
|
-
else
|
2376
|
-
# Asciidoctor < 1.5.6
|
2377
|
-
text = doc.catalog[:ids][refid]
|
2375
|
+
if ::Asciidoctor::AbstractNode === (ref = doc.catalog[:refs][refid])
|
2376
|
+
text = ref.xreftext node.attr 'xrefstyle', nil, true
|
2378
2377
|
end
|
2379
2378
|
end
|
2380
2379
|
%(<a anchor="#{derive_anchor_from_id refid}">#{text || "[#{refid}]"}</a>).gsub ']', ']'
|
@@ -2410,12 +2409,16 @@ module Asciidoctor
|
|
2410
2409
|
end
|
2411
2410
|
|
2412
2411
|
def convert_inline_callout node
|
2413
|
-
if (
|
2414
|
-
|
2415
|
-
%(<color rgb="#{conum_color}">#{conum_glyph node.text.to_i}</color>)
|
2412
|
+
if (conum_font_family = @theme.conum_font_family) == font_name
|
2413
|
+
result = conum_glyph node.text.to_i
|
2416
2414
|
else
|
2417
|
-
conum_glyph node.text.to_i
|
2415
|
+
result = %(<font name="#{conum_font_family}">#{conum_glyph node.text.to_i}</font>)
|
2418
2416
|
end
|
2417
|
+
if (conum_font_color = @theme.conum_font_color)
|
2418
|
+
# NOTE CMYK value gets flattened here, but is restored by formatted text parser
|
2419
|
+
result = %(<color rgb="#{conum_font_color}">#{result}</font>)
|
2420
|
+
end
|
2421
|
+
result
|
2419
2422
|
end
|
2420
2423
|
|
2421
2424
|
def convert_inline_footnote node
|
@@ -2501,7 +2504,7 @@ module Asciidoctor
|
|
2501
2504
|
if ::File.readable? image_path
|
2502
2505
|
width_attr = (width = preresolve_explicit_width node.attributes) ? %( width="#{width}") : ''
|
2503
2506
|
fit_attr = (fit = node.attr 'fit', nil, false) ? %( fit="#{fit}") : ''
|
2504
|
-
img = %(<img src="#{image_path}" format="#{image_format}" alt="
|
2507
|
+
img = %(<img src="#{image_path}" format="#{image_format}" alt="#{encode_quotes node.attr 'alt'}"#{width_attr}#{fit_attr}>)
|
2505
2508
|
else
|
2506
2509
|
logger.warn %(image to embed not found or not readable: #{image_path}) unless scratch?
|
2507
2510
|
img = %([#{node.attr 'alt'}])
|
@@ -2889,8 +2892,8 @@ module Asciidoctor
|
|
2889
2892
|
if opts.delete :dry_run
|
2890
2893
|
height = nil
|
2891
2894
|
dry_run do
|
2892
|
-
move_down
|
2893
|
-
height =
|
2895
|
+
move_down 0.001 # HACK: force top margin to be applied
|
2896
|
+
height = layout_caption subject, opts
|
2894
2897
|
end
|
2895
2898
|
return height
|
2896
2899
|
end
|
@@ -3421,12 +3424,12 @@ module Asciidoctor
|
|
3421
3424
|
end
|
3422
3425
|
tot_width = 0
|
3423
3426
|
side_colspecs = colspecs.map {|col, spec|
|
3424
|
-
if (alignment_char = spec.chr).to_i.to_s
|
3425
|
-
alignment = AlignmentTable[alignment_char] || :left
|
3426
|
-
rel_width = (spec.slice 1, spec.length).to_f
|
3427
|
-
else
|
3427
|
+
if (alignment_char = spec.chr).to_i.to_s == alignment_char
|
3428
3428
|
alignment = :left
|
3429
3429
|
rel_width = spec.to_f
|
3430
|
+
else
|
3431
|
+
alignment = AlignmentTable[alignment_char] || :left
|
3432
|
+
rel_width = (spec.slice 1, spec.length).to_f
|
3430
3433
|
end
|
3431
3434
|
tot_width += rel_width
|
3432
3435
|
[col, { align: alignment, width: rel_width, x: 0 }]
|
@@ -3583,13 +3586,13 @@ module Asciidoctor
|
|
3583
3586
|
|
3584
3587
|
def write pdf_doc, target
|
3585
3588
|
if target.respond_to? :write
|
3586
|
-
target = ::QuantifiableStdout.new
|
3589
|
+
target = ::QuantifiableStdout.new $stdout if target == $stdout
|
3587
3590
|
pdf_doc.render target
|
3588
3591
|
else
|
3589
3592
|
pdf_doc.render_file target
|
3590
3593
|
# QUESTION restore attributes first?
|
3591
3594
|
@pdfmark&.generate_file target
|
3592
|
-
(Optimizer.new @optimize, pdf_doc.min_version).
|
3595
|
+
(Optimizer.new @optimize, pdf_doc.min_version).optimize_file target if @optimize
|
3593
3596
|
end
|
3594
3597
|
# write scratch document if debug is enabled (or perhaps DEBUG_STEPS env)
|
3595
3598
|
#get_scratch_document.render_file 'scratch.pdf'
|
@@ -3694,7 +3697,7 @@ module Asciidoctor
|
|
3694
3697
|
end
|
3695
3698
|
# FIXME: due to the calculation error logged in #789, we must advance page even when content is split across pages
|
3696
3699
|
advance_page if (opts.fetch :split_from_top, true) && block_height > cursor && !at_page_top?
|
3697
|
-
caption_height = (node = opts[:caption_node]) && node.title? ? (layout_caption node, category: category)
|
3700
|
+
caption_height = (node = opts[:caption_node]) && node.title? ? (layout_caption node, category: category) : 0
|
3698
3701
|
float do
|
3699
3702
|
remaining_height = block_height - caption_height
|
3700
3703
|
initial_page = true
|
@@ -4081,24 +4084,22 @@ module Asciidoctor
|
|
4081
4084
|
unlink_tmp_file tmp_image.path
|
4082
4085
|
nil
|
4083
4086
|
end
|
4084
|
-
#
|
4085
|
-
elsif
|
4086
|
-
|
4087
|
-
|
4087
|
+
# NOTE: this will catch a classloader resource path on JRuby (e.g., uri:classloader:/path/to/image)
|
4088
|
+
elsif ::File.absolute_path? image_path
|
4089
|
+
::File.absolute_path image_path
|
4090
|
+
elsif !(is_uri = node.is_uri? image_path) && imagesdir && (::File.absolute_path? imagesdir)
|
4091
|
+
::File.absolute_path image_path, imagesdir
|
4092
|
+
elsif is_uri || (imagesdir && (node.is_uri? imagesdir) && (image_path = node.normalize_web_path image_path, imagesdir, false))
|
4093
|
+
if !allow_uri_read
|
4088
4094
|
logger.warn %(allow-uri-read is not enabled; cannot embed remote image: #{image_path}) unless scratch?
|
4089
4095
|
return
|
4090
|
-
|
4091
|
-
if @tmp_files.key? image_path
|
4096
|
+
elsif @tmp_files.key? image_path
|
4092
4097
|
return @tmp_files[image_path]
|
4093
|
-
elsif cache_uri
|
4094
|
-
Helpers.require_library 'open-uri/cached', 'open-uri-cached' unless defined? ::OpenURI::Cache
|
4095
|
-
else
|
4096
|
-
::OpenURI
|
4097
4098
|
end
|
4098
4099
|
tmp_image = ::Tempfile.create ['image-', image_format && %(.#{image_format})]
|
4099
4100
|
tmp_image.binmode if (binary = image_format != 'svg')
|
4100
4101
|
begin
|
4101
|
-
|
4102
|
+
load_open_uri.open_uri(image_path, (binary ? 'rb' : 'r')) {|fd| tmp_image.write fd.read }
|
4102
4103
|
tmp_image.close
|
4103
4104
|
@tmp_files[image_path] = tmp_image.path
|
4104
4105
|
rescue
|
@@ -4285,11 +4286,12 @@ module Asciidoctor
|
|
4285
4286
|
result = {}
|
4286
4287
|
center = nil
|
4287
4288
|
(value.split ' ', 2).each do |keyword|
|
4288
|
-
|
4289
|
+
case keyword
|
4290
|
+
when 'left', 'right'
|
4289
4291
|
result[:position] = keyword.to_sym
|
4290
|
-
|
4292
|
+
when 'top', 'bottom'
|
4291
4293
|
result[:vposition] = keyword.to_sym
|
4292
|
-
|
4294
|
+
when 'center'
|
4293
4295
|
center = true
|
4294
4296
|
end
|
4295
4297
|
end
|
@@ -4348,6 +4350,14 @@ module Asciidoctor
|
|
4348
4350
|
link_annotation [image_x, (image_y - image_height), (image_x + image_width), image_y], Border: [0, 0, 0], A: { Type: :Action, S: :URI, URI: uri.as_pdf }
|
4349
4351
|
end
|
4350
4352
|
|
4353
|
+
def load_open_uri
|
4354
|
+
if @cache_uri && !(defined? ::OpenURI::Cache)
|
4355
|
+
# disable URI caching if library fails to load
|
4356
|
+
@cache_uri = false if (Helpers.require_library 'open-uri/cached', 'open-uri-cached', :warn).nil?
|
4357
|
+
end
|
4358
|
+
::OpenURI
|
4359
|
+
end
|
4360
|
+
|
4351
4361
|
def remove_tmp_files
|
4352
4362
|
@tmp_files.reject! {|_, path| path ? (unlink_tmp_file path) : true }
|
4353
4363
|
end
|