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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +68 -1
  3. data/{LICENSE.adoc → LICENSE} +3 -4
  4. data/NOTICE.adoc +4 -6
  5. data/README.adoc +139 -46
  6. data/asciidoctor-pdf.gemspec +11 -14
  7. data/bin/asciidoctor-pdf-optimize +1 -1
  8. data/docs/theming-guide.adoc +26 -22
  9. data/lib/asciidoctor/pdf/converter.rb +88 -78
  10. data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +3 -2
  11. data/lib/asciidoctor/pdf/ext/core/file.rb +4 -5
  12. data/lib/asciidoctor/pdf/ext/core.rb +0 -1
  13. data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +1 -1
  14. data/lib/asciidoctor/pdf/ext/pdf-core.rb +15 -0
  15. data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +4 -13
  16. data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +28 -2
  17. data/lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb +1 -1
  18. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +15 -0
  19. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +28 -7
  20. data/lib/asciidoctor/pdf/ext/prawn-svg.rb +0 -1
  21. data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
  22. data/lib/asciidoctor/pdf/ext/pygments.rb +11 -9
  23. data/lib/asciidoctor/pdf/ext.rb +0 -1
  24. data/lib/asciidoctor/pdf/formatted_text/fragment_position_renderer.rb +5 -1
  25. data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +9 -2
  26. data/lib/asciidoctor/pdf/formatted_text/transform.rb +6 -4
  27. data/lib/asciidoctor/pdf/index_catalog.rb +1 -1
  28. data/lib/asciidoctor/pdf/optimizer.rb +40 -12
  29. data/lib/asciidoctor/pdf/pdfmark.rb +1 -2
  30. data/lib/asciidoctor/pdf/text_transformer.rb +10 -71
  31. data/lib/asciidoctor/pdf/theme_loader.rb +1 -1
  32. data/lib/asciidoctor/pdf/version.rb +1 -1
  33. data/lib/asciidoctor/pdf.rb +3 -0
  34. metadata +21 -63
  35. data/lib/asciidoctor/pdf/ext/core/numeric.rb +0 -26
  36. data/lib/asciidoctor/pdf/ext/prawn-svg/interface.rb +0 -14
  37. data/lib/asciidoctor/pdf/ext/prawn-templates.rb +0 -7
@@ -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.3.0'
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/master/CHANGELOG.adoc',
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|LICENSE|NOTICE|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$/
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', '>= 1.5.3', '< 3.0.0'
37
- s.add_runtime_dependency 'prawn', '~> 2.2.0'
38
- # NOTE ttfunk 1.6 generates TT instructions ghostscript cannot process, so lock the version of ttfunk
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.30.0'
44
- s.add_runtime_dependency 'prawn-icon', '~> 2.5.0'
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 'thread_safe', '~> 0.3.0'
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.9.0'
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.3.0'
53
+ s.add_development_dependency 'chunky_png', '~> 1.4.0'
57
54
  end
@@ -17,4 +17,4 @@ end
17
17
 
18
18
  quality = args[0] == '--quality' ? args[1].to_s : ''
19
19
 
20
- (Asciidoctor::PDF::Optimizer.new quality).generate_file filename
20
+ (Asciidoctor::PDF::Optimizer.new quality).optimize_file filename
@@ -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/master/data/themes/default-theme.yml[default-theme.yml] file from the source repository.
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: 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.
756
- To do so, you can either a) prefix the path of the bundled font in the theme file with the segment `GEM_FONTS_DIR` (e.g., `GEM_FONTS_DIR/mplus1p-regular-fallback.ttf`, or b) use relative paths in the theme file and 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"`).
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/master/data/themes/base-theme.yml[base theme].
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/master/data/themes/default-theme.yml[default theme] has a different set of values which are not shown in this guide.
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
- . The `toc` value only applies if the toc is in the default location (before the first page of the body).
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
- |iamge:
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` attribute.
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
- * alpha:: partially complete and unstable
3643
- * beta:: feature complete and undergoing testing
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 catagory control the style of the footnotes list at the end of the chapter (book) or document (otherwise).
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
- . The `toc` value only applies if the toc is in the default location (before the first page of the body).
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 thoughout the theme file as it's a core feature of YAML.
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 `+&#169;+`, hexidecimal character references like `+&#x20ac;+`, and inline formatting (e.g., bold, italic, monospace).
4769
+ You can also use built-in AsciiDoc text replacements like `+(C)+`, numeric character references like `+&#169;+`, hexadecimal character references like `+&#x20ac;+`, 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 slighly nudge the image up or down.
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 hexidecimal format (e.g., #ff0000 for red).
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., `\&apos;`).
5222
- You can change the font color using `rgb` attribue on the `color` element (e.g., `<color rgb="#ff0000">`) and the font family and size using `name` and `size` attributes on the `font` element, respectively (e.g., `<font name="sans" size="12">`).
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 horizonal rule) to make it render like a ribbon:
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], and make sure only the following options are selected (equivalent to the flags 0x90 + 0x08):
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/master/scripts[scripts directory] of this project.
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.create ::Asciidoctor::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+(?:[\-]\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 = [*theme.font_fallbacks]
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
- @optimize = doc.attr 'optimize'
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
- if type == :part
571
+ case type
572
+ when :part
575
573
  layout_part_title sect, title, align: align, level: hlevel
576
- elsif type == :chapter
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
- theme_font :footnotes do
613
- (title = doc.attr 'footnotes-title') && (layout_caption title, category: :footnotes)
614
- item_spacing = @theme.footnotes_item_spacing || 0
615
- fns.each do |fn|
616
- layout_prose %(<a id="_footnotedef_#{index = fn.index}">#{DummyText}</a>[<a anchor="_footnoteref_#{index}">#{index}</a>] #{fn.text}), margin_bottom: item_spacing, hyphenate: true
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 = [*subjects].first.text
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
- if cache_uri
1595
- Helpers.require_library 'open-uri/cached', 'open-uri-cached' unless defined? ::OpenURI::Cache
1596
- else
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 = @capabilities[:syntax_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
- conum_color = @theme.conum_font_color
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
- line << (conum_color ? { text: conum_text, color: conum_color } : { text: conum_text })
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' || ((role.split ' ').include? '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 (refs = doc.catalog[:refs])
2372
- if ::Asciidoctor::AbstractNode === (ref = refs[refid])
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 ']', '&#93;'
@@ -2410,12 +2409,16 @@ module Asciidoctor
2410
2409
  end
2411
2410
 
2412
2411
  def convert_inline_callout node
2413
- if (conum_color = @theme.conum_font_color)
2414
- # NOTE CMYK value gets flattened here, but is restored by formatted text parser
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="[#{encode_quotes node.attr 'alt'}]"#{width_attr}#{fit_attr}>)
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 1 # HACK: force top margin to be applied
2893
- height = (layout_caption subject, opts) - 1
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 != alignment_char
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 STDOUT if target == STDOUT
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).generate_file target if @optimize && ((defined? ::Asciidoctor::PDF::Optimizer) || !(Helpers.require_library OptimizerRequirePath, 'rghost', :warn).nil?)
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) - 1 : 0
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
- # handle case when image is a URI
4085
- elsif (node.is_uri? image_path) ||
4086
- (imagesdir && (node.is_uri? imagesdir) && (image_path = node.normalize_web_path image_path, imagesdir, false))
4087
- unless allow_uri_read
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
- end
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
- ::OpenURI.open_uri(image_path, (binary ? 'rb' : 'r')) {|fd| tmp_image.write fd.read }
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
- if keyword == 'left' || keyword == 'right'
4289
+ case keyword
4290
+ when 'left', 'right'
4289
4291
  result[:position] = keyword.to_sym
4290
- elsif keyword == 'top' || keyword == 'bottom'
4292
+ when 'top', 'bottom'
4291
4293
  result[:vposition] = keyword.to_sym
4292
- elsif keyword == 'center'
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