asciidoctor-pdf 1.5.0.beta.1 → 1.5.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +26 -0
- data/README.adoc +2 -2
- data/asciidoctor-pdf.gemspec +3 -3
- data/bin/asciidoctor-pdf +1 -0
- data/data/fonts/ABOUT-mplus1mn-subset +24 -0
- data/data/fonts/ABOUT-mplus1p-subset +25 -0
- data/data/fonts/ABOUT-notoserif-subset +25 -0
- data/data/fonts/{LICENSE-mplus-testflight-58 → LICENSE-mplus} +2 -2
- data/data/fonts/{LICENSE-noto-2015-06-05 → LICENSE-notoserif} +0 -0
- data/data/fonts/mplus1mn-bold-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-bold-subset.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-regular-ascii-conums.ttf +0 -0
- data/data/fonts/mplus1mn-regular-subset.ttf +0 -0
- data/data/fonts/mplus1p-regular-fallback.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 +8 -1
- data/data/themes/default-theme.yml +22 -7
- data/data/themes/default-with-fallback-font-theme.yml +4 -4
- data/docs/theming-guide.adoc +459 -44
- data/lib/asciidoctor-pdf.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/abstract_block.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/document.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/image.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/list.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/list_item.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/logging_shim.rb +1 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/section.rb +1 -0
- data/lib/asciidoctor-pdf/converter.rb +227 -137
- data/lib/asciidoctor-pdf/core_ext.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/array.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/hash.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/numeric.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/object.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/quantifiable_stdout.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/regexp.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/string.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/formatter.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/inline_destination_marker.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/inline_image_arranger.rb +2 -1
- data/lib/asciidoctor-pdf/formatted_text/inline_image_renderer.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/inline_text_aligner.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/parser.rb +19 -6
- data/lib/asciidoctor-pdf/formatted_text/parser.treetop +2 -3
- data/lib/asciidoctor-pdf/formatted_text/text_background_and_border_renderer.rb +1 -0
- data/lib/asciidoctor-pdf/formatted_text/transform.rb +51 -3
- data/lib/asciidoctor-pdf/implicit_header_processor.rb +1 -0
- data/lib/asciidoctor-pdf/index_catalog.rb +1 -0
- data/lib/asciidoctor-pdf/measurements.rb +1 -0
- data/lib/asciidoctor-pdf/pdf-core_ext.rb +1 -0
- data/lib/asciidoctor-pdf/pdf-core_ext/page.rb +26 -0
- data/lib/asciidoctor-pdf/pdf-core_ext/pdf_object.rb +1 -0
- data/lib/asciidoctor-pdf/pdfmark.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-svg_ext.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-svg_ext/interface.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-table_ext.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-table_ext/cell.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-table_ext/cell/asciidoc.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-table_ext/cell/text.rb +1 -0
- data/lib/asciidoctor-pdf/prawn-templates_ext.rb +1 -0
- data/lib/asciidoctor-pdf/prawn_ext.rb +1 -0
- data/lib/asciidoctor-pdf/prawn_ext/coderay_encoder.rb +6 -5
- data/lib/asciidoctor-pdf/prawn_ext/extensions.rb +11 -17
- data/lib/asciidoctor-pdf/prawn_ext/font/afm.rb +15 -8
- data/lib/asciidoctor-pdf/prawn_ext/formatted_text/fragment.rb +1 -0
- data/lib/asciidoctor-pdf/prawn_ext/images.rb +2 -1
- data/lib/asciidoctor-pdf/roman_numeral.rb +1 -0
- data/lib/asciidoctor-pdf/rouge_ext.rb +1 -0
- data/lib/asciidoctor-pdf/rouge_ext/formatters/prawn.rb +1 -0
- data/lib/asciidoctor-pdf/rouge_ext/themes/asciidoctor_pdf_default.rb +1 -0
- data/lib/asciidoctor-pdf/rouge_ext/themes/bw.rb +1 -0
- data/lib/asciidoctor-pdf/sanitizer.rb +1 -0
- data/lib/asciidoctor-pdf/temporary_path.rb +1 -0
- data/lib/asciidoctor-pdf/theme_loader.rb +13 -13
- data/lib/asciidoctor-pdf/ttfunk_ext.rb +1 -0
- data/lib/asciidoctor-pdf/version.rb +2 -1
- data/lib/asciidoctor/pdf.rb +1 -0
- data/lib/asciidoctor/pdf/version.rb +1 -0
- metadata +15 -15
- data/lib/asciidoctor-pdf/core_ext/ostruct.rb +0 -8
data/lib/asciidoctor-pdf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
# TODO cleanup imports...decide what belongs in asciidoctor-pdf.rb
|
3
3
|
require 'prawn'
|
4
4
|
require_relative 'ttfunk_ext'
|
@@ -58,34 +58,37 @@ class Converter < ::Prawn::Document
|
|
58
58
|
PageLayouts = [:portrait, :landscape]
|
59
59
|
PageSides = [:recto, :verso]
|
60
60
|
(PDFVersions = { '1.3' => 1.3, '1.4' => 1.4, '1.5' => 1.5, '1.6' => 1.6, '1.7' => 1.7 }).default = 1.4
|
61
|
-
LF =
|
62
|
-
DoubleLF =
|
63
|
-
TAB =
|
64
|
-
InnerIndent =
|
61
|
+
LF = ?\n
|
62
|
+
DoubleLF = LF * 2
|
63
|
+
TAB = ?\t
|
64
|
+
InnerIndent = LF + ' '
|
65
65
|
# a no-break space is used to replace a leading space to prevent Prawn from trimming indentation
|
66
66
|
# a leading zero-width space can't be used as it gets dropped when calculating the line width
|
67
|
-
GuardedIndent =
|
68
|
-
GuardedInnerIndent =
|
67
|
+
GuardedIndent = ?\u00a0
|
68
|
+
GuardedInnerIndent = LF + GuardedIndent
|
69
69
|
TabRx = /\t/
|
70
70
|
TabIndentRx = /^\t+/
|
71
|
-
NoBreakSpace =
|
72
|
-
|
73
|
-
|
74
|
-
DummyText = %(\u0000)
|
71
|
+
NoBreakSpace = ?\u00a0
|
72
|
+
ZeroWidthSpace = ?\u200b
|
73
|
+
DummyText = ?\u0000
|
75
74
|
DotLeaderTextDefault = '. '
|
76
|
-
EmDash =
|
77
|
-
RightPointer =
|
78
|
-
LowercaseGreekA =
|
75
|
+
EmDash = ?\u2014
|
76
|
+
RightPointer = ?\u25ba
|
77
|
+
LowercaseGreekA = ?\u03b1
|
79
78
|
Bullets = {
|
80
|
-
disc:
|
81
|
-
circle:
|
82
|
-
square:
|
79
|
+
disc: ?\u2022,
|
80
|
+
circle: ?\u25e6,
|
81
|
+
square: ?\u25aa,
|
83
82
|
none: ''
|
84
83
|
}
|
85
84
|
# NOTE Default theme font uses ballot boxes from FontAwesome
|
86
85
|
BallotBox = {
|
87
|
-
checked:
|
88
|
-
unchecked:
|
86
|
+
checked: ?\u2611,
|
87
|
+
unchecked: ?\u2610
|
88
|
+
}
|
89
|
+
ConumSets = {
|
90
|
+
'circled' => (?\u2460..?\u2473).to_a,
|
91
|
+
'filled' => (?\u2776..?\u277f).to_a + (?\u24eb..?\u24f4).to_a,
|
89
92
|
}
|
90
93
|
SimpleAttributeRefRx = /(?<!\\)\{\w+(?:[\-]\w+)*\}/
|
91
94
|
MeasurementRxt = '\\d+(?:\\.\\d+)?(?:in|cm|mm|p[txc])?'
|
@@ -98,10 +101,14 @@ class Converter < ::Prawn::Document
|
|
98
101
|
UriSchemeBoundaryRx = /(?<=:\/\/)/
|
99
102
|
LineScanRx = /\n|.+/
|
100
103
|
BlankLineRx = /\n{2,}/
|
101
|
-
WhitespaceChars =
|
104
|
+
WhitespaceChars = ' ' + TAB + LF
|
102
105
|
SourceHighlighters = ['coderay', 'pygments', 'rouge'].to_set
|
103
106
|
PygmentsBgColorRx = /^\.highlight +{ *background: *#([^;]+);/
|
104
107
|
ViewportWidth = ::Module.new
|
108
|
+
(TitleStyles = {
|
109
|
+
'toc' => [:numbered_title],
|
110
|
+
'basic' => [:title],
|
111
|
+
}).default = [:numbered_title, formal: true]
|
105
112
|
|
106
113
|
def initialize backend, opts
|
107
114
|
super
|
@@ -122,7 +129,6 @@ class Converter < ::Prawn::Document
|
|
122
129
|
|
123
130
|
def convert node, name = nil, opts = {}
|
124
131
|
method_name = %(convert_#{name ||= node.node_name})
|
125
|
-
result = nil
|
126
132
|
if respond_to? method_name
|
127
133
|
# NOTE we prepend the prefix "convert_" to avoid conflict with Prawn methods
|
128
134
|
result = send method_name, node
|
@@ -175,29 +181,16 @@ class Converter < ::Prawn::Document
|
|
175
181
|
blk_0 = blk_1 = preface = nil
|
176
182
|
end
|
177
183
|
|
178
|
-
|
179
|
-
# NOTE on_page_create is not called for imported pages, front and back cover pages, and other image pages
|
180
|
-
on_page_create do
|
181
|
-
# NOTE we assume in prepress that physical page number reflects page side
|
182
|
-
if @media == 'prepress' && (next_page_margin = @page_margin_by_side[page_side]) != page_margin
|
183
|
-
set_page_margin next_page_margin
|
184
|
-
end
|
185
|
-
# TODO implement as a watermark (on top)
|
186
|
-
if (bg_image = @page_bg_image[page_side])
|
187
|
-
canvas { image bg_image[0], ({ position: :center, vposition: :center }.merge bg_image[1]) }
|
188
|
-
elsif @page_bg_color && @page_bg_color != 'FFFFFF'
|
189
|
-
fill_absolute_bounds @page_bg_color
|
190
|
-
end
|
191
|
-
end if respond_to? :on_page_create
|
184
|
+
on_page_create &(method :init_page)
|
192
185
|
|
193
186
|
layout_cover_page doc, :front
|
194
187
|
if (insert_title_page = doc.doctype == 'book' || (doc.attr? 'title-page'))
|
195
188
|
layout_title_page doc
|
196
189
|
# NOTE a new page will already be started if the cover image is a PDF
|
197
|
-
start_new_page unless
|
190
|
+
start_new_page unless page.empty?
|
198
191
|
else
|
199
192
|
# NOTE a new page will already be started if the cover image is a PDF
|
200
|
-
start_new_page unless
|
193
|
+
start_new_page unless page.empty?
|
201
194
|
body_start_page_number = page_number
|
202
195
|
if doc.header? && !doc.notitle
|
203
196
|
theme_font :heading, level: 1 do
|
@@ -208,7 +201,7 @@ class Converter < ::Prawn::Document
|
|
208
201
|
end
|
209
202
|
|
210
203
|
# NOTE font must be set before toc dry run to ensure dry run size is accurate
|
211
|
-
font @theme.base_font_family, size: @theme.base_font_size, style: @theme.base_font_style.to_sym
|
204
|
+
font @theme.base_font_family, size: @theme.base_font_size, style: (@theme.base_font_style || :normal).to_sym
|
212
205
|
|
213
206
|
num_toc_levels = (doc.attr 'toclevels', 2).to_i
|
214
207
|
if (insert_toc = (doc.attr? 'toc') && doc.sections?)
|
@@ -271,7 +264,7 @@ class Converter < ::Prawn::Document
|
|
271
264
|
|
272
265
|
# NOTE delete orphaned page (a page was created but there was no additional content)
|
273
266
|
# QUESTION should we delete page if document is empty? (leaving no pages?)
|
274
|
-
delete_page if
|
267
|
+
delete_page if page.empty? && page_count > 1
|
275
268
|
|
276
269
|
toc_page_nums = insert_toc ? (layout_toc doc, num_toc_levels, toc_page_nums.first, num_front_matter_pages[1], toc_start) : []
|
277
270
|
|
@@ -322,27 +315,32 @@ class Converter < ::Prawn::Document
|
|
322
315
|
else
|
323
316
|
@ppbook = false
|
324
317
|
end
|
325
|
-
# QUESTION should ThemeLoader
|
318
|
+
# QUESTION should ThemeLoader handle registering fonts instead?
|
326
319
|
register_fonts theme.font_catalog, (doc.attr 'scripts', 'latin'), (doc.attr 'pdf-fontsdir', ThemeLoader::FontsDir)
|
320
|
+
default_kerning theme.base_font_kerning != 'none'
|
321
|
+
@fallback_fonts = [*theme.font_fallbacks]
|
327
322
|
if (bg_image = resolve_background_image doc, theme, 'page-background-image') && bg_image[0]
|
328
323
|
@page_bg_image = { verso: bg_image, recto: bg_image }
|
329
324
|
else
|
330
325
|
@page_bg_image = { verso: nil, recto: nil }
|
331
326
|
end
|
332
327
|
if (bg_image = resolve_background_image doc, theme, 'page-background-image-verso')
|
333
|
-
@page_bg_image[:verso] = bg_image[0]
|
328
|
+
@page_bg_image[:verso] = bg_image[0] && bg_image
|
334
329
|
end
|
335
|
-
if (bg_image = resolve_background_image doc, theme, 'page-background-image-recto')
|
336
|
-
@page_bg_image[:recto] = bg_image[0]
|
330
|
+
if (bg_image = resolve_background_image doc, theme, 'page-background-image-recto')
|
331
|
+
@page_bg_image[:recto] = bg_image[0] && bg_image
|
337
332
|
end
|
338
333
|
@page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
|
339
|
-
@
|
340
|
-
@font_color = theme.base_font_color
|
334
|
+
@font_color = theme.base_font_color || '000000'
|
341
335
|
@base_align = (align = doc.attr 'text-align') && (TextAlignmentNames.include? align) ? align : theme.base_align
|
342
336
|
@text_transform = nil
|
343
337
|
@list_numerals = []
|
344
338
|
@list_bullets = []
|
345
339
|
@footnotes = []
|
340
|
+
@conum_glyphs = ConumSets[@theme.conum_glyphs || 'circled'] || (@theme.conum_glyphs.split ',').map {|r|
|
341
|
+
from, to = r.rstrip.split '-', 2
|
342
|
+
to ? ((get_char from)..(get_char to)).to_a : [(get_char from)]
|
343
|
+
}.flatten
|
346
344
|
@index = IndexCatalog.new
|
347
345
|
# NOTE we have to init Pdfmark class here while we have reference to the doc
|
348
346
|
@pdfmark = (doc.attr? 'pdfmark') ? (Pdfmark.new doc) : nil
|
@@ -354,12 +352,22 @@ class Converter < ::Prawn::Document
|
|
354
352
|
@theme ||= begin
|
355
353
|
if (theme = doc.options[:pdf_theme])
|
356
354
|
@themesdir = theme.__dir__ || (doc.attr 'pdf-themesdir') || (doc.attr 'pdf-stylesdir')
|
355
|
+
elsif (theme_name = (doc.attr 'pdf-theme') || (doc.attr 'pdf-style'))
|
356
|
+
theme = ThemeLoader.load_theme theme_name, (theme_dir = (doc.attr 'pdf-themesdir') || (doc.attr 'pdf-stylesdir'))
|
357
|
+
@themesdir = theme.__dir__
|
357
358
|
else
|
358
|
-
|
359
|
-
theme = ThemeLoader.load_theme theme_name, ((doc.attr 'pdf-themesdir') || (doc.attr 'pdf-stylesdir'))
|
359
|
+
theme = ThemeLoader.load_theme
|
360
360
|
@themesdir = theme.__dir__
|
361
361
|
end
|
362
362
|
theme
|
363
|
+
rescue
|
364
|
+
if theme_dir
|
365
|
+
message = %(could not locate or load the pdf theme `#{theme_name}' in #{::File.absolute_path theme_dir})
|
366
|
+
else
|
367
|
+
message = %(could not locate or load the built-in pdf theme `#{theme_name}')
|
368
|
+
end
|
369
|
+
logger.error message
|
370
|
+
raise
|
363
371
|
end
|
364
372
|
end
|
365
373
|
|
@@ -472,6 +480,23 @@ class Converter < ::Prawn::Document
|
|
472
480
|
info
|
473
481
|
end
|
474
482
|
|
483
|
+
# NOTE init_page is called within a float context
|
484
|
+
# NOTE init_page is not called for imported pages, front and back cover pages, and other image pages
|
485
|
+
def init_page *args
|
486
|
+
# NOTE we assume in prepress that physical page number reflects page side
|
487
|
+
if @media == 'prepress' && (next_page_margin = @page_margin_by_side[page_side]) != page_margin
|
488
|
+
set_page_margin next_page_margin
|
489
|
+
end
|
490
|
+
# TODO implement as a watermark (on top)
|
491
|
+
if (bg_image = @page_bg_image[page_side])
|
492
|
+
canvas { image bg_image[0], ({ position: :center, vposition: :center }.merge bg_image[1]) }
|
493
|
+
page.tare_content_stream
|
494
|
+
elsif @page_bg_color && @page_bg_color != 'FFFFFF'
|
495
|
+
fill_absolute_bounds @page_bg_color
|
496
|
+
page.tare_content_stream
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
475
500
|
def convert_section sect, opts = {}
|
476
501
|
if sect.sectname == 'abstract'
|
477
502
|
# HACK cheat a bit to hide this section from TOC; TOC should filter these sections
|
@@ -493,7 +518,7 @@ class Converter < ::Prawn::Document
|
|
493
518
|
end
|
494
519
|
else
|
495
520
|
# FIXME smarter calculation here!!
|
496
|
-
start_new_page unless at_page_top? || cursor > (height_of title) + @theme.heading_margin_top + @theme.heading_margin_bottom + (@theme.base_line_height_length * 1.5)
|
521
|
+
start_new_page unless at_page_top? || cursor > (height_of title) + @theme.heading_margin_top + @theme.heading_margin_bottom + ((@theme.base_line_height_length || (font_size * @theme.base_line_height)) * 1.5)
|
497
522
|
end
|
498
523
|
# QUESTION should we store pdf-page-start, pdf-anchor & pdf-destination in internal map?
|
499
524
|
sect.set_attr 'pdf-page-start', (start_pgnum = page_number)
|
@@ -711,7 +736,7 @@ class Converter < ::Prawn::Document
|
|
711
736
|
vposition: label_valign,
|
712
737
|
width: label_width,
|
713
738
|
height: box_height,
|
714
|
-
fallback_font_name:
|
739
|
+
fallback_font_name: fallback_svg_font_name,
|
715
740
|
enable_web_requests: allow_uri_read,
|
716
741
|
enable_file_requests_with_root: (::File.dirname icon_path)
|
717
742
|
if (icon_height = (svg_size = svg_obj.document.sizing).output_height) > box_height
|
@@ -962,9 +987,7 @@ class Converter < ::Prawn::Document
|
|
962
987
|
end
|
963
988
|
add_dest_for_block node if node.id
|
964
989
|
@list_numerals ||= []
|
965
|
-
|
966
|
-
# \u2460 = circled one, \u24f5 = double circled one, \u278b = negative circled one
|
967
|
-
@list_numerals << %(\u2460)
|
990
|
+
@list_numerals << 1
|
968
991
|
#stroke_horizontal_rule @theme.caption_border_bottom_color
|
969
992
|
line_metrics = calc_line_metrics @theme.base_line_height
|
970
993
|
node.items.each_with_index do |item, idx|
|
@@ -980,13 +1003,13 @@ class Converter < ::Prawn::Document
|
|
980
1003
|
|
981
1004
|
def convert_colist_item node
|
982
1005
|
marker_width = nil
|
1006
|
+
@list_numerals << (index = @list_numerals.pop).next
|
983
1007
|
theme_font :conum do
|
984
|
-
marker_width = rendered_width_of_string %(#{conum_glyph
|
1008
|
+
marker_width = rendered_width_of_string %(#{marker = conum_glyph index}x)
|
985
1009
|
float do
|
986
1010
|
bounding_box [0, cursor], width: marker_width do
|
987
|
-
@list_numerals << (index = @list_numerals.pop).next
|
988
1011
|
theme_font :conum do
|
989
|
-
layout_prose
|
1012
|
+
layout_prose marker, align: :center, line_height: @theme.conum_line_height, inline_format: false, margin: 0
|
990
1013
|
end
|
991
1014
|
end
|
992
1015
|
end
|
@@ -1014,26 +1037,25 @@ class Converter < ::Prawn::Document
|
|
1014
1037
|
terms = [*terms]
|
1015
1038
|
# NOTE don't orphan the terms, allow for at least one line of content
|
1016
1039
|
# FIXME extract ensure_space (or similar) method
|
1017
|
-
advance_page if cursor < @theme.base_line_height_length * (terms.size + 1)
|
1040
|
+
advance_page if cursor < (@theme.base_line_height_length || (font_size * @theme.base_line_height)) * (terms.size + 1)
|
1018
1041
|
terms.each do |term|
|
1019
1042
|
# FIXME layout_prose should pass style downward when parsing formatted text
|
1020
1043
|
#layout_prose term.text, style: @theme.description_list_term_font_style.to_sym, margin_top: 0, margin_bottom: @theme.description_list_term_spacing, align: :left
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1044
|
+
case @theme.description_list_term_font_style.to_s
|
1045
|
+
when 'bold'
|
1046
|
+
term_text = %(<strong>#{term.text}</strong>)
|
1047
|
+
when 'italic'
|
1048
|
+
term_text = %(<em>#{term.text}</em>)
|
1049
|
+
when 'bold_italic'
|
1050
|
+
term_text = %(<strong><em>#{term.text}</em></strong>)
|
1051
|
+
else
|
1052
|
+
term_text = term.text
|
1029
1053
|
end
|
1030
1054
|
layout_prose term_text, margin_top: 0, margin_bottom: @theme.description_list_term_spacing, align: :left
|
1031
1055
|
end
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
end
|
1036
|
-
end
|
1056
|
+
indent(@theme.description_list_description_indent || 0) do
|
1057
|
+
convert_content_for_list_item desc, :dlist_desc
|
1058
|
+
end if desc
|
1037
1059
|
end
|
1038
1060
|
end
|
1039
1061
|
end
|
@@ -1136,12 +1158,12 @@ class Converter < ::Prawn::Document
|
|
1136
1158
|
if node.style == 'unstyled'
|
1137
1159
|
# unstyled takes away all indentation
|
1138
1160
|
list_indent = 0
|
1139
|
-
elsif (list_indent = @theme.outline_list_indent) > 0
|
1161
|
+
elsif (list_indent = @theme.outline_list_indent || 0) > 0
|
1140
1162
|
# no-bullet aligns text with left-hand side of bullet position (as though there's no bullet)
|
1141
|
-
list_indent = [list_indent - (rendered_width_of_string %(#{node.context == :ulist ?
|
1163
|
+
list_indent = [list_indent - (rendered_width_of_string %(#{node.context == :ulist ? ?\u2022 : '1.'}x)), 0].max
|
1142
1164
|
end
|
1143
1165
|
else
|
1144
|
-
list_indent = @theme.outline_list_indent
|
1166
|
+
list_indent = @theme.outline_list_indent || 0
|
1145
1167
|
end
|
1146
1168
|
indent list_indent do
|
1147
1169
|
node.items.each do |item|
|
@@ -1154,8 +1176,7 @@ class Converter < ::Prawn::Document
|
|
1154
1176
|
# However, don't leave gap at the bottom if list is nested in an outline list
|
1155
1177
|
unless complex || (node.nested? && node.parent.parent.outline?)
|
1156
1178
|
# correct bottom margin of last item
|
1157
|
-
|
1158
|
-
margin_bottom list_margin_bottom - @theme.outline_list_item_spacing
|
1179
|
+
margin_bottom((@theme.prose_margin_bottom || 0) - (@theme.outline_list_item_spacing || 0))
|
1159
1180
|
end
|
1160
1181
|
end
|
1161
1182
|
|
@@ -1264,7 +1285,7 @@ class Converter < ::Prawn::Document
|
|
1264
1285
|
if ::File.readable? image_path
|
1265
1286
|
# NOTE import_page automatically advances to next page afterwards
|
1266
1287
|
# QUESTION should we add destination to top of imported page?
|
1267
|
-
return import_page image_path, replace:
|
1288
|
+
return import_page image_path, replace: page.empty? if image_format == 'pdf'
|
1268
1289
|
elsif image_format == 'pdf'
|
1269
1290
|
logger.warn %(pdf to insert not found or not readable: #{image_path}) unless scratch?
|
1270
1291
|
# QUESTION should we use alt text in this case?
|
@@ -1311,7 +1332,7 @@ class Converter < ::Prawn::Document
|
|
1311
1332
|
svg_obj = ::Prawn::SVG::Interface.new svg_data, self,
|
1312
1333
|
position: alignment,
|
1313
1334
|
width: width,
|
1314
|
-
fallback_font_name:
|
1335
|
+
fallback_font_name: fallback_svg_font_name,
|
1315
1336
|
enable_web_requests: allow_uri_read,
|
1316
1337
|
enable_file_requests_with_root: file_request_root
|
1317
1338
|
rendered_w = (svg_size = svg_obj.document.sizing).output_width
|
@@ -1331,16 +1352,17 @@ class Converter < ::Prawn::Document
|
|
1331
1352
|
rendered_w = (svg_size = svg_obj.resize height: (rendered_h = available_h)).output_width
|
1332
1353
|
end
|
1333
1354
|
end
|
1355
|
+
image_y = y
|
1334
1356
|
add_dest_for_block node if node.id
|
1335
1357
|
# NOTE workaround to fix Prawn not adding fill and stroke commands on page that only has an image;
|
1336
1358
|
# breakage occurs when running content (stamps) are added to page
|
1359
|
+
# seems to be resolved as of Prawn 2.2.2
|
1337
1360
|
update_colors if graphic_state.color_space.empty?
|
1338
1361
|
# NOTE prawn-svg 0.24.0, 0.25.0, & 0.25.1 didn't restore font after call to draw (see mogest/prawn-svg#80)
|
1339
|
-
# NOTE cursor
|
1362
|
+
# NOTE cursor advances automatically
|
1340
1363
|
svg_obj.draw
|
1341
1364
|
if (link = node.attr 'link', nil, false)
|
1342
|
-
|
1343
|
-
link_annotation link_box, Border: [0, 0, 0], A: { Type: :Action, S: :URI, URI: link.as_pdf }
|
1365
|
+
add_link_to_image link, { width: rendered_w, height: rendered_h }, position: alignment, y: image_y
|
1344
1366
|
end
|
1345
1367
|
else
|
1346
1368
|
# FIXME this code really needs to be better organized!
|
@@ -1360,21 +1382,19 @@ class Converter < ::Prawn::Document
|
|
1360
1382
|
rendered_w, rendered_h = image_info.calc_image_dimensions height: (rendered_h = available_h)
|
1361
1383
|
end
|
1362
1384
|
end
|
1363
|
-
|
1364
|
-
if (link = node.attr 'link', nil, false)
|
1365
|
-
img_x, img_y = image_position rendered_w, rendered_h, position: alignment
|
1366
|
-
link_box = [img_x, (img_y - rendered_h), (img_x + rendered_w), img_y]
|
1367
|
-
end
|
1368
|
-
image_top = cursor
|
1385
|
+
image_y = y
|
1369
1386
|
add_dest_for_block node if node.id
|
1370
1387
|
# NOTE workaround to fix Prawn not adding fill and stroke commands on page that only has an image;
|
1371
1388
|
# breakage occurs when running content (stamps) are added to page
|
1389
|
+
# seems to be resolved as of Prawn 2.2.2
|
1372
1390
|
update_colors if graphic_state.color_space.empty?
|
1373
1391
|
# NOTE specify both width and height to avoid recalculation
|
1374
1392
|
embed_image image_obj, image_info, width: rendered_w, height: rendered_h, position: alignment
|
1375
|
-
|
1393
|
+
if (link = node.attr 'link', nil, false)
|
1394
|
+
add_link_to_image link, { width: rendered_w, height: rendered_h }, position: alignment, y: image_y
|
1395
|
+
end
|
1376
1396
|
# NOTE Asciidoctor disables automatic advancement of cursor for raster images, so move cursor manually
|
1377
|
-
move_down rendered_h if
|
1397
|
+
move_down rendered_h if y == image_y
|
1378
1398
|
end
|
1379
1399
|
end
|
1380
1400
|
layout_caption node, side: :bottom if node.title?
|
@@ -1629,7 +1649,7 @@ class Converter < ::Prawn::Document
|
|
1629
1649
|
end
|
1630
1650
|
|
1631
1651
|
pad_box @theme.code_padding do
|
1632
|
-
typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height),
|
1652
|
+
typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height || @theme.base_line_height),
|
1633
1653
|
# QUESTION should we require the code_font_color to be set?
|
1634
1654
|
color: (@theme.code_font_color || @font_color),
|
1635
1655
|
size: adjusted_font_size
|
@@ -1712,12 +1732,7 @@ class Converter < ::Prawn::Document
|
|
1712
1732
|
end
|
1713
1733
|
|
1714
1734
|
def conum_glyph number
|
1715
|
-
|
1716
|
-
# FIXME use lookup table for glyphs instead of relying on counting
|
1717
|
-
# \u2460 = circled one, \u24f5 = double circled one, \u278b = negative circled one
|
1718
|
-
glyph = %(\u2460)
|
1719
|
-
(number - 1).times { glyph = glyph.next }
|
1720
|
-
glyph
|
1735
|
+
@conum_glyphs[number - 1]
|
1721
1736
|
end
|
1722
1737
|
|
1723
1738
|
# Adds guards to preserve indentation
|
@@ -1952,7 +1967,7 @@ class Converter < ::Prawn::Document
|
|
1952
1967
|
(alignment = (node.roles & BlockAlignmentNames)[-1])
|
1953
1968
|
alignment = alignment.to_sym
|
1954
1969
|
else
|
1955
|
-
alignment = :left
|
1970
|
+
alignment = (theme.table_align || :left).to_sym
|
1956
1971
|
end
|
1957
1972
|
|
1958
1973
|
caption_side = (theme.table_caption_side || :top).to_sym
|
@@ -1960,7 +1975,8 @@ class Converter < ::Prawn::Document
|
|
1960
1975
|
|
1961
1976
|
table_settings = {
|
1962
1977
|
header: table_header,
|
1963
|
-
position
|
1978
|
+
# NOTE position is handled by this method
|
1979
|
+
position: :left,
|
1964
1980
|
cell_style: {
|
1965
1981
|
# NOTE the border color and style of the outer frame is set later
|
1966
1982
|
border_color: table_grid_color,
|
@@ -1986,11 +2002,23 @@ class Converter < ::Prawn::Document
|
|
1986
2002
|
|
1987
2003
|
theme_margin :block, :top
|
1988
2004
|
|
2005
|
+
left_padding = right_padding = nil
|
1989
2006
|
table table_data, table_settings do
|
1990
2007
|
# NOTE call width to capture resolved table width
|
1991
2008
|
table_width = width
|
1992
2009
|
caption_max_width = caption_max_width == 'fit-content' ? table_width : nil
|
1993
2010
|
@pdf.layout_table_caption node, alignment, caption_max_width if node.title? && caption_side == :top
|
2011
|
+
# NOTE align using padding instead of bounding_box as prawn-table does
|
2012
|
+
# using a bounding_box across pages mangles the margin box of subsequent pages
|
2013
|
+
if alignment != :left && table_width != (this_bounds = @pdf.bounds).width
|
2014
|
+
if alignment == :center
|
2015
|
+
left_padding = right_padding = (this_bounds.width - width) * 0.5
|
2016
|
+
this_bounds.add_left_padding left_padding
|
2017
|
+
this_bounds.add_right_padding right_padding
|
2018
|
+
else # :right
|
2019
|
+
this_bounds.add_left_padding(left_padding = this_bounds.width - width)
|
2020
|
+
end
|
2021
|
+
end
|
1994
2022
|
if grid == 'none' && frame == 'none'
|
1995
2023
|
if table_header
|
1996
2024
|
rows(0).tap do |r|
|
@@ -2049,6 +2077,10 @@ class Converter < ::Prawn::Document
|
|
2049
2077
|
#end
|
2050
2078
|
end
|
2051
2079
|
end
|
2080
|
+
if left_padding
|
2081
|
+
bounds.subtract_left_padding left_padding
|
2082
|
+
bounds.subtract_right_padding right_padding if right_padding
|
2083
|
+
end
|
2052
2084
|
layout_table_caption node, alignment, caption_max_width, caption_side if node.title? && caption_side == :bottom
|
2053
2085
|
theme_margin :block, :bottom
|
2054
2086
|
end
|
@@ -2078,7 +2110,7 @@ class Converter < ::Prawn::Document
|
|
2078
2110
|
end
|
2079
2111
|
|
2080
2112
|
if at_page_top?
|
2081
|
-
if page_layout && page_layout != page.layout &&
|
2113
|
+
if page_layout && page_layout != page.layout && page.empty?
|
2082
2114
|
delete_page
|
2083
2115
|
advance_page layout: page_layout
|
2084
2116
|
end
|
@@ -2244,22 +2276,29 @@ class Converter < ::Prawn::Document
|
|
2244
2276
|
else
|
2245
2277
|
size_attr = ''
|
2246
2278
|
end
|
2247
|
-
|
2248
|
-
|
2279
|
+
if icon_set == 'fa'
|
2280
|
+
# legacy name from Font Awesome < 5
|
2281
|
+
if (remapped_icon_name = resolve_legacy_icon_name icon_name)
|
2282
|
+
requested_icon_name = icon_name
|
2283
|
+
icon_set, icon_name = remapped_icon_name.split '-', 2
|
2284
|
+
glyph = (icon_font_data icon_set).unicode icon_name
|
2285
|
+
logger.info { %(#{requested_icon_name} icon found in deprecated fa icon set; using #{icon_name} from #{icon_set} icon set instead) }
|
2286
|
+
# new name in Font Awesome >= 5 (but document is configured to use fa icon set)
|
2287
|
+
else
|
2249
2288
|
font_data = nil
|
2250
|
-
resolved_icon_set = FontAwesomeIconSets.find {|candidate| (font_data = icon_font_data candidate).unicode icon_name rescue nil }
|
2251
|
-
if resolved_icon_set
|
2289
|
+
if (resolved_icon_set = FontAwesomeIconSets.find {|candidate| (font_data = icon_font_data candidate).unicode icon_name rescue nil })
|
2252
2290
|
icon_set = resolved_icon_set
|
2253
|
-
|
2254
|
-
|
2255
|
-
raise
|
2291
|
+
glyph = font_data.unicode icon_name
|
2292
|
+
logger.info { %(#{icon_name} icon not found in deprecated fa icon set; using match found in #{resolved_icon_set} icon set instead) }
|
2256
2293
|
end
|
2257
|
-
else
|
2258
|
-
font_data = icon_font_data icon_set
|
2259
2294
|
end
|
2295
|
+
else
|
2296
|
+
glyph = (icon_font_data icon_set).unicode icon_name rescue nil
|
2297
|
+
end
|
2298
|
+
if glyph
|
2260
2299
|
# TODO support rotate and flip attributes
|
2261
|
-
%(<font name="#{icon_set}"#{size_attr}>#{
|
2262
|
-
|
2300
|
+
%(<font name="#{icon_set}"#{size_attr}>#{glyph}</font>)
|
2301
|
+
else
|
2263
2302
|
logger.warn %(#{icon_name} is not a valid icon name in the #{icon_set} icon set)
|
2264
2303
|
%([#{node.attr 'alt'}])
|
2265
2304
|
end
|
@@ -2316,9 +2355,9 @@ class Converter < ::Prawn::Document
|
|
2316
2355
|
|
2317
2356
|
def convert_inline_kbd node
|
2318
2357
|
if (keys = node.attr 'keys').size == 1
|
2319
|
-
%(<
|
2358
|
+
%(<key>#{keys[0]}</key>)
|
2320
2359
|
else
|
2321
|
-
keys.map {|key| %(<
|
2360
|
+
keys.map {|key| %(<key>#{key}</key>) }.join @theme.key_separator || '+'
|
2322
2361
|
end
|
2323
2362
|
end
|
2324
2363
|
|
@@ -2347,9 +2386,9 @@ class Converter < ::Prawn::Document
|
|
2347
2386
|
when :subscript
|
2348
2387
|
open, close, is_tag = ['<sub>', '</sub>', true]
|
2349
2388
|
when :double
|
2350
|
-
open, close, is_tag = [
|
2389
|
+
open, close, is_tag = [?\u201c, ?\u201d, false]
|
2351
2390
|
when :single
|
2352
|
-
open, close, is_tag = [
|
2391
|
+
open, close, is_tag = [?\u2018, ?\u2019, false]
|
2353
2392
|
#when :asciimath, :latexmath
|
2354
2393
|
else
|
2355
2394
|
open, close, is_tag = [nil, nil, false]
|
@@ -2372,16 +2411,24 @@ class Converter < ::Prawn::Document
|
|
2372
2411
|
def layout_title_page doc
|
2373
2412
|
return unless doc.header? && !doc.notitle
|
2374
2413
|
|
2375
|
-
|
2414
|
+
# NOTE a new page may have already been started at this point, so decide what to do with it
|
2415
|
+
if page.empty?
|
2416
|
+
page.reset_content if (recycle = @ppbook ? verso_page? : true)
|
2417
|
+
elsif @ppbook && verso_page?
|
2418
|
+
start_new_page
|
2419
|
+
end
|
2420
|
+
|
2421
|
+
side = recycle ? page_side : (page_side page_number + 1)
|
2422
|
+
prev_bg_image = @page_bg_image[side]
|
2376
2423
|
prev_bg_color = @page_bg_color
|
2377
|
-
|
2424
|
+
if (bg_image = resolve_background_image doc, @theme, 'title-page-background-image')
|
2425
|
+
@page_bg_image[side] = bg_image[0] && bg_image
|
2426
|
+
end
|
2378
2427
|
if (bg_color = resolve_theme_color :title_page_background_color)
|
2379
2428
|
@page_bg_color = bg_color
|
2380
2429
|
end
|
2381
|
-
|
2382
|
-
|
2383
|
-
start_new_page if @ppbook && verso_page?
|
2384
|
-
@page_bg_image[side] = prev_bg_image if prev_bg_image
|
2430
|
+
recycle ? (init_page self) : start_new_page
|
2431
|
+
@page_bg_image[side] = prev_bg_image if bg_image
|
2385
2432
|
@page_bg_color = prev_bg_color if bg_color
|
2386
2433
|
|
2387
2434
|
# IMPORTANT this is the first page created, so we need to set the base font
|
@@ -2540,7 +2587,7 @@ class Converter < ::Prawn::Document
|
|
2540
2587
|
string = transform_text string, transform
|
2541
2588
|
end
|
2542
2589
|
margin_top top_margin
|
2543
|
-
typeset_text string, calc_line_metrics((opts.delete :line_height) || @theme[%(heading_h#{opts[:level]}_line_height)] || @theme.heading_line_height), {
|
2590
|
+
typeset_text string, calc_line_metrics((opts.delete :line_height) || @theme[%(heading_h#{opts[:level]}_line_height)] || @theme.heading_line_height || @theme.base_line_height), {
|
2544
2591
|
color: @font_color,
|
2545
2592
|
inline_format: true,
|
2546
2593
|
align: @base_align.to_sym
|
@@ -2646,10 +2693,12 @@ class Converter < ::Prawn::Document
|
|
2646
2693
|
go_to_page toc_page_number unless (page_number == toc_page_number) || scratch?
|
2647
2694
|
start_page_number = page_number
|
2648
2695
|
@y = start_at if start_at
|
2649
|
-
|
2650
|
-
theme_font :
|
2651
|
-
|
2652
|
-
|
2696
|
+
unless (toc_title = doc.attr 'toc-title').nil_or_empty?
|
2697
|
+
theme_font :heading, level: 2 do
|
2698
|
+
theme_font :toc_title do
|
2699
|
+
toc_title_align = (@theme.toc_title_align || @theme.heading_h2_align || @theme.heading_align || @base_align).to_sym
|
2700
|
+
layout_heading toc_title, align: toc_title_align
|
2701
|
+
end
|
2653
2702
|
end
|
2654
2703
|
end
|
2655
2704
|
# QUESTION should we skip this whole method if num_levels < 0?
|
@@ -2779,6 +2828,7 @@ class Converter < ::Prawn::Document
|
|
2779
2828
|
sectlevels = (@theme[%(#{periphery}_sectlevels)] || 2).to_i
|
2780
2829
|
sections = doc.find_by(context: :section) {|sect| sect.level <= sectlevels && sect != header } || []
|
2781
2830
|
|
2831
|
+
title_method = TitleStyles[@theme[%(#{periphery}_title_style)]]
|
2782
2832
|
# FIXME we need a proper model for all this page counting
|
2783
2833
|
# FIXME we make a big assumption that part & chapter start on new pages
|
2784
2834
|
# index parts, chapters and sections by the visual page number on which they start
|
@@ -2790,16 +2840,16 @@ class Converter < ::Prawn::Document
|
|
2790
2840
|
page_num = (sect.attr 'pdf-page-start').to_i - skip_pagenums
|
2791
2841
|
if is_book && ((sect_is_part = sect.part?) || sect.chapter?)
|
2792
2842
|
if sect_is_part
|
2793
|
-
part_start_pages[page_num] ||=
|
2843
|
+
part_start_pages[page_num] ||= sect.send(*title_method)
|
2794
2844
|
else
|
2795
|
-
chapter_start_pages[page_num] ||=
|
2845
|
+
chapter_start_pages[page_num] ||= sect.send(*title_method)
|
2796
2846
|
if sect.sectname == 'appendix' && !part_start_pages.empty?
|
2797
2847
|
# FIXME need a better way to indicate that part has ended
|
2798
2848
|
part_start_pages[page_num] = ''
|
2799
2849
|
end
|
2800
2850
|
end
|
2801
2851
|
else
|
2802
|
-
sect_title = trailing_section_start_pages[page_num] = sect.
|
2852
|
+
sect_title = trailing_section_start_pages[page_num] = sect.send(*title_method)
|
2803
2853
|
section_start_pages[page_num] ||= sect_title
|
2804
2854
|
end
|
2805
2855
|
end
|
@@ -2923,7 +2973,15 @@ class Converter < ::Prawn::Document
|
|
2923
2973
|
bounding_box [left, bounds.top - trim_styles[:padding][0] - trim_styles[:content_offset]], width: colwidth, height: trim_styles[:content_height] do
|
2924
2974
|
# NOTE image vposition respects padding; use negative image_vertical_align value to revert
|
2925
2975
|
image_opts = content[1].merge position: colspec[:align], vposition: trim_styles[:img_valign]
|
2926
|
-
|
2976
|
+
begin
|
2977
|
+
image_info = image content[0], image_opts
|
2978
|
+
if (image_link = content[2])
|
2979
|
+
image_info = { width: image_info.scaled_width, height: image_info.scaled_height } unless image_opts[:format] == 'svg'
|
2980
|
+
add_link_to_image image_link, image_info, image_opts
|
2981
|
+
end
|
2982
|
+
rescue
|
2983
|
+
logger.warn %(could not embed image in running content: #{content[0]}; #{$!.message})
|
2984
|
+
end
|
2927
2985
|
end
|
2928
2986
|
end
|
2929
2987
|
when ::String
|
@@ -3063,7 +3121,7 @@ class Converter < ::Prawn::Document
|
|
3063
3121
|
if ::File.readable? (image_path = (ThemeLoader.resolve_theme_asset $1, @themesdir))
|
3064
3122
|
image_attrs = (AttributeList.new $2).parse ['alt', 'width']
|
3065
3123
|
image_opts = resolve_image_options image_path, image_attrs, container_size: [colspec_dict[side][position][:width], trim_styles[:content_height]], format: image_attrs['format']
|
3066
|
-
side_content[position] = [image_path, image_opts]
|
3124
|
+
side_content[position] = [image_path, image_opts, image_attrs['link']]
|
3067
3125
|
else
|
3068
3126
|
# NOTE allows inline image handler to report invalid reference and replace with alt text
|
3069
3127
|
side_content[position] = %(image:#{image_path}[#{$2}])
|
@@ -3131,7 +3189,9 @@ class Converter < ::Prawn::Document
|
|
3131
3189
|
# FIXME link to title page if there's a cover page (skip cover page and ensure blank page)
|
3132
3190
|
page title: doctitle, destination: (document.dest_top 1)
|
3133
3191
|
end
|
3134
|
-
|
3192
|
+
unless toc_page_nums.none? || (toc_title = doc.attr 'toc-title').nil_or_empty?
|
3193
|
+
page title: toc_title, destination: (document.dest_top toc_page_nums.first)
|
3194
|
+
end
|
3135
3195
|
# QUESTION any way to get add_outline_level to invoke in the context of the outline?
|
3136
3196
|
document.add_outline_level self, doc.sections, num_levels
|
3137
3197
|
end
|
@@ -3175,9 +3235,6 @@ class Converter < ::Prawn::Document
|
|
3175
3235
|
(font_catalog || {}).each do |key, styles|
|
3176
3236
|
register_font key => styles.map {|style, path| [style.to_sym, (font_path path, fonts_dir)]}.to_h
|
3177
3237
|
end
|
3178
|
-
|
3179
|
-
# FIXME read kerning setting from theme!
|
3180
|
-
default_kerning true
|
3181
3238
|
end
|
3182
3239
|
|
3183
3240
|
def font_path font_file, fonts_dir
|
@@ -3185,8 +3242,8 @@ class Converter < ::Prawn::Document
|
|
3185
3242
|
::File.absolute_path font_file, fonts_dir
|
3186
3243
|
end
|
3187
3244
|
|
3188
|
-
def
|
3189
|
-
@theme.svg_font_family || @theme.base_font_family
|
3245
|
+
def fallback_svg_font_name
|
3246
|
+
@theme.svg_fallback_font_family || @theme.svg_font_family || @theme.base_font_family
|
3190
3247
|
end
|
3191
3248
|
|
3192
3249
|
attr_reader :allow_uri_read
|
@@ -3231,7 +3288,7 @@ class Converter < ::Prawn::Document
|
|
3231
3288
|
# Insert a margin space at the specified side unless cursor is at the top of the page.
|
3232
3289
|
# Start a new page if n value is greater than remaining space on page.
|
3233
3290
|
def margin n, side
|
3234
|
-
unless n == 0 || at_page_top?
|
3291
|
+
unless (n || 0) == 0 || at_page_top?
|
3235
3292
|
# NOTE use low-level cursor calculation to workaround cursor bug in column_box context
|
3236
3293
|
if y - reference_bounds.absolute_bottom > n
|
3237
3294
|
move_down n
|
@@ -3599,7 +3656,7 @@ class Converter < ::Prawn::Document
|
|
3599
3656
|
image_opts = {
|
3600
3657
|
enable_file_requests_with_root: (::File.dirname image_path),
|
3601
3658
|
enable_web_requests: allow_uri_read,
|
3602
|
-
fallback_font_name:
|
3659
|
+
fallback_font_name: fallback_svg_font_name,
|
3603
3660
|
format: 'svg',
|
3604
3661
|
}
|
3605
3662
|
else
|
@@ -3694,7 +3751,9 @@ class Converter < ::Prawn::Document
|
|
3694
3751
|
str_to_pt width
|
3695
3752
|
end
|
3696
3753
|
elsif opts[:use_fallback] && (width = @theme.image_width)
|
3697
|
-
if width
|
3754
|
+
if ::Numeric === width
|
3755
|
+
width
|
3756
|
+
elsif (width = width.to_s).end_with? '%'
|
3698
3757
|
(width.to_f / 100) * max_width
|
3699
3758
|
elsif opts[:support_vw] && (width.end_with? 'vw')
|
3700
3759
|
(width.chomp 'vw').extend ViewportWidth
|
@@ -3739,6 +3798,33 @@ class Converter < ::Prawn::Document
|
|
3739
3798
|
end
|
3740
3799
|
end
|
3741
3800
|
|
3801
|
+
def add_link_to_image uri, image_info, image_opts
|
3802
|
+
image_width = image_info[:width]
|
3803
|
+
image_height = image_info[:height]
|
3804
|
+
|
3805
|
+
case image_opts[:position]
|
3806
|
+
when :center
|
3807
|
+
image_x = bounds.left_side + (bounds.width - image_width) * 0.5
|
3808
|
+
when :right
|
3809
|
+
image_x = bounds.right_side - image_width
|
3810
|
+
else # :left or not set
|
3811
|
+
image_x = bounds.left_side
|
3812
|
+
end
|
3813
|
+
|
3814
|
+
case image_opts[:vposition]
|
3815
|
+
when :top
|
3816
|
+
image_y = bounds.absolute_top
|
3817
|
+
when :center
|
3818
|
+
image_y = bounds.absolute_top - (bounds.height - image_height) * 0.5
|
3819
|
+
when :bottom
|
3820
|
+
image_y = bounds.absolute_bottom + image_height
|
3821
|
+
else
|
3822
|
+
image_y = y
|
3823
|
+
end unless (image_y = image_opts[:y])
|
3824
|
+
|
3825
|
+
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 }
|
3826
|
+
end
|
3827
|
+
|
3742
3828
|
# QUESTION is there a better way to do this?
|
3743
3829
|
# I suppose we could have @tmp_files as an instance variable on converter instead
|
3744
3830
|
# It might be sufficient to delete temporary files once per conversion
|
@@ -3778,6 +3864,10 @@ class Converter < ::Prawn::Document
|
|
3778
3864
|
end
|
3779
3865
|
end
|
3780
3866
|
|
3867
|
+
def get_char code
|
3868
|
+
(code.start_with? '\u') ? ([((code.slice 2, code.length).to_i 16)].pack 'U1') : code
|
3869
|
+
end
|
3870
|
+
|
3781
3871
|
# QUESTION move to prawn/extensions.rb?
|
3782
3872
|
def init_scratch_prototype
|
3783
3873
|
@save_state = nil
|