asciidoctor-pdf 2.0.0.beta.1 → 2.0.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -252,6 +252,15 @@ module Asciidoctor
252
252
  @y == @margin_box.absolute_top
253
253
  end
254
254
 
255
+ # Prevents at_page_top? from returning true while yielding to the specified block.
256
+ #
257
+ def conceal_page_top
258
+ margin_box.instance_variable_set :@y, (old_top = margin_box.absolute_top) + 0.0001
259
+ yield
260
+ ensure
261
+ margin_box.instance_variable_set :@y, old_top
262
+ end
263
+
255
264
  # Returns whether the current page is the last page in the document.
256
265
  #
257
266
  def last_page?
@@ -410,20 +419,11 @@ module Asciidoctor
410
419
  def parse_text string, options = {}
411
420
  return [] if string.nil?
412
421
 
413
- options = options.dup
414
- if (format_option = options.delete :inline_format)
422
+ if (format_option = options[:inline_format])
415
423
  format_option = [] unless ::Array === format_option
416
- fragments = text_formatter.format string, *format_option
417
- else
418
- fragments = [text: string]
419
- end
420
-
421
- if (color = options.delete :color)
422
- fragments.map do |fragment|
423
- fragment[:color] ? fragment : (fragment.merge color: color)
424
- end
424
+ text_formatter.format string, *format_option
425
425
  else
426
- fragments
426
+ [text: string]
427
427
  end
428
428
  end
429
429
 
@@ -435,7 +435,8 @@ module Asciidoctor
435
435
  @no_text_printed = box.nothing_printed?
436
436
  @all_text_printed = box.everything_printed?
437
437
 
438
- if ((defined? @final_gap) && @final_gap) || (options[:first_line] && !(@no_text_printed || @all_text_printed))
438
+ if ((defined? @final_gap) && @final_gap) ||
439
+ (options[:first_line] && (options[:final_gap] || !(@no_text_printed || @all_text_printed)))
439
440
  self.y -= box.height + box.line_gap + box.leading
440
441
  else
441
442
  self.y -= box.height
@@ -453,31 +454,50 @@ module Asciidoctor
453
454
  # renderered. It's necessary to use low-level APIs in this method so we only style the first line and not the
454
455
  # remaining lines (which is the default behavior in Prawn).
455
456
  def text_with_formatted_first_line string, first_line_options, options
456
- color = options.delete :color
457
+ if (first_line_font_color = first_line_options.delete :color)
458
+ other_lines_font_color, options[:color] = options[:color], first_line_font_color
459
+ end
457
460
  fragments = parse_text string, options
458
461
  # NOTE: the low-level APIs we're using don't recognize the :styles option, so we must resolve
459
- # NOTE: disabled until we have a need for it
462
+ # NOTE: disabled until we have a need for it; currently handled in convert_abstract
460
463
  #if (styles = options.delete :styles)
461
464
  # options[:style] = resolve_font_style styles
462
465
  #end
463
466
  if (first_line_styles = first_line_options.delete :styles)
464
467
  first_line_options[:style] = resolve_font_style first_line_styles
465
468
  end
466
- first_line_color = (first_line_options.delete :color) || color
469
+ first_line_text_transform = first_line_options.delete :text_transform
467
470
  options = options.merge document: self
471
+ text_indent = options.delete :indent_paragraphs
468
472
  # QUESTION: should we merge more carefully here? (hand-select keys?)
469
473
  first_line_options = (options.merge first_line_options).merge single_line: true, first_line: true
470
474
  box = ::Prawn::Text::Formatted::Box.new fragments, first_line_options
471
- # NOTE: get remaining_fragments before we add color to fragments on first line
472
- if (text_indent = options.delete :indent_paragraphs)
475
+ if text_indent
473
476
  remaining_fragments = indent text_indent do
474
477
  box.render dry_run: true
475
478
  end
476
479
  else
477
480
  remaining_fragments = box.render dry_run: true
478
481
  end
479
- # NOTE: color must be applied per-fragment
480
- fragments.each {|fragment| fragment[:color] ||= first_line_color }
482
+ if first_line_text_transform
483
+ # NOTE: applying text transform here could alter the wrapping, so we need to isolate first line and shrink to fit
484
+ first_line_text = (box.instance_variable_get :@printed_lines)[0]
485
+ unless first_line_text == fragments[0][:text]
486
+ original_fragments, fragments = fragments, []
487
+ original_fragments.reduce '' do |traced, fragment|
488
+ fragments << fragment
489
+ # NOTE: we could just do a length comparison here
490
+ if (traced += fragment[:text]).start_with? first_line_text
491
+ fragment[:text] = fragment[:text][0...-(traced.length - first_line_text.length)]
492
+ break
493
+ end
494
+ traced
495
+ end
496
+ end
497
+ fragments.each {|fragment| fragment[:text] = transform_text fragment[:text], first_line_text_transform }
498
+ first_line_options[:overflow] = :shrink_to_fit
499
+ first_line_options[:final_gap] = first_line_options[:force_justify] = true unless remaining_fragments.empty?
500
+ end
481
501
  if text_indent
482
502
  indent text_indent do
483
503
  fill_formatted_text_box fragments, first_line_options
@@ -486,8 +506,7 @@ module Asciidoctor
486
506
  fill_formatted_text_box fragments, first_line_options
487
507
  end
488
508
  unless remaining_fragments.empty?
489
- # NOTE: color must be applied per-fragment
490
- remaining_fragments.each {|fragment| fragment[:color] ||= color }
509
+ options[:color] = other_lines_font_color if first_line_font_color
491
510
  remaining_fragments = fill_formatted_text_box remaining_fragments, options
492
511
  draw_remaining_formatted_text_on_new_pages remaining_fragments, options
493
512
  end
@@ -1018,7 +1037,15 @@ module Asciidoctor
1018
1037
  state.on_page_create_callback = delegate
1019
1038
  end
1020
1039
 
1021
- # NOTE: only used in dry_run since that's when DetectEmptyFirstPage is active
1040
+ # This method delegates to the provided block, then tares (i.e., resets) the content stream of
1041
+ # the initial page.
1042
+ #
1043
+ # The purpose of this method is to ink content while making it appear as though the page is
1044
+ # empty. This technique allows the caller to detect whether any subsequent content was written
1045
+ # to the page following the content inked by the block. It's often used to keep the title of a
1046
+ # content block with the block's first child.
1047
+ #
1048
+ # NOTE: this method should only used inside dry_run since that's when DetectEmptyFirstPage is active
1022
1049
  def tare_first_page_content_stream
1023
1050
  return yield unless DetectEmptyFirstPage === (delegate = state.on_page_create_callback)
1024
1051
  on_page_create_called = nil
@@ -4,13 +4,18 @@ Prawn::Text::Formatted::Box.prepend (Module.new do
4
4
  include Asciidoctor::Logging
5
5
 
6
6
  def initialize formatted_text, options = {}
7
+ if (color = options[:color]) && !formatted_text.empty?
8
+ formatted_text = formatted_text.map {|fragment| fragment[:color] ? fragment : (fragment.merge color: color) }
9
+ end
7
10
  super
8
11
  formatted_text[0][:normalize_line_height] = true if options[:normalize_line_height] && !formatted_text.empty?
9
12
  options[:extensions]&.each {|extension| extend extension }
13
+ extend Prawn::Text::Formatted::IndentedParagraphWrap if (@indent_paragraphs = options[:indent_paragraphs])
10
14
  if (bottom_gutter = options[:bottom_gutter]) && bottom_gutter > 0
11
15
  @bottom_gutter = bottom_gutter
12
16
  extend Prawn::Text::Formatted::ProtectBottomGutter
13
17
  end
18
+ @force_justify = options[:force_justify]
14
19
  end
15
20
 
16
21
  def draw_fragment_overlay_styles fragment
@@ -71,6 +76,15 @@ Prawn::Text::Formatted::Box.prepend (Module.new do
71
76
  end
72
77
  end
73
78
 
79
+ # Override method to force text justification when :force_justify option is set (typically for rendering a single line)
80
+ def word_spacing_for_this_line
81
+ if @align == :justify && (@force_justify || (@line_wrap.space_count > 0 && !@line_wrap.paragraph_finished?))
82
+ (available_width - @line_wrap.width) / @line_wrap.space_count
83
+ else
84
+ 0
85
+ end
86
+ end
87
+
74
88
  # Override method in super class to provide support for a tuple consisting of alignment and offset
75
89
  def process_vertical_alignment text
76
90
  return super if Symbol === (valign = @vertical_align)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prawn::Text::Formatted
4
+ module IndentedParagraphWrap
5
+ # Override Prawn::Text::Formatted::Box#wrap method to add support for :indent_paragraphs to (formatted_)text_box.
6
+ def wrap array
7
+ initialize_wrap array
8
+ stop = nil
9
+ until stop
10
+ if (first_line_indent = @indent_paragraphs) && @printed_lines.empty?
11
+ @width -= first_line_indent
12
+ stop = @document.indent(first_line_indent) { wrap_and_print_line }
13
+ @width += first_line_indent
14
+ else
15
+ stop = wrap_and_print_line
16
+ end
17
+ end
18
+ @text = @printed_lines.join ?\n
19
+ @everything_printed = @arranger.finished?
20
+ @arranger.unconsumed
21
+ end
22
+
23
+ def wrap_and_print_line
24
+ @line_wrap.wrap_line \
25
+ document: @document,
26
+ kerning: @kerning,
27
+ width: @width,
28
+ arranger: @arranger,
29
+ disable_wrap_by_char: @disable_wrap_by_char
30
+ if enough_height_for_this_line?
31
+ move_baseline_down
32
+ print_line
33
+ @single_line || @arranger.finished?
34
+ else
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
@@ -41,17 +41,10 @@ module Prawn
41
41
  extent = @pdf.dry_run keep_together: true, single_page: true do
42
42
  push_scratch parent_doc
43
43
  doc.catalog[:footnotes] = parent_doc.catalog[:footnotes]
44
- if padding_y > 0
45
- move_down padding_y
46
- #elsif at_page_top?
47
- else
48
- # TODO: encapsulate this logic to force top margin to be applied
49
- margin_box.instance_variable_set :@y, margin_box.absolute_top + 0.0001
50
- end
51
44
  # NOTE: we should be able to use cell.max_width, but returns 0 in some conditions (like when colspan > 1)
52
45
  indent cell.padding_left, bounds.width - cell.width + cell.padding_right do
53
- # TODO: truncate margin bottom of last block
54
- traverse cell.content
46
+ move_down padding_y if padding_y > 0
47
+ conceal_page_top { traverse cell.content }
55
48
  end
56
49
  pop_scratch parent_doc
57
50
  doc.catalog[:footnotes] = parent_doc.catalog[:footnotes]
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # the following are organized under the Asciidoctor::Prawn namespace
4
+ require_relative 'prawn/document/column_box'
4
5
  require_relative 'prawn/font_metric_cache'
5
6
  require_relative 'prawn/font/afm'
6
7
  require_relative 'prawn/images'
7
8
  require_relative 'prawn/formatted_text/arranger'
8
9
  require_relative 'prawn/formatted_text/box'
9
10
  require_relative 'prawn/formatted_text/fragment'
11
+ require_relative 'prawn/formatted_text/indented_paragraph_wrap'
10
12
  require_relative 'prawn/formatted_text/protect_bottom_gutter'
11
13
  require_relative 'prawn/extensions'
@@ -24,14 +24,19 @@ module Asciidoctor
24
24
  @arranger.unconsumed.unshift highlight_line if highlight_line
25
25
  @arranger.unconsumed.unshift linenum_spacer.dup
26
26
  end
27
- @line_wrap.wrap_line document: @document, kerning: @kerning, width: available_width, arranger: @arranger, disable_wrap_by_char: @disable_wrap_by_char
27
+ @line_wrap.wrap_line \
28
+ document: @document,
29
+ kerning: @kerning,
30
+ width: @width,
31
+ arranger: @arranger,
32
+ disable_wrap_by_char: @disable_wrap_by_char
28
33
  if enough_height_for_this_line?
29
34
  move_baseline_down
30
35
  print_line
36
+ stop = @arranger.finished?
31
37
  else
32
38
  stop = true
33
39
  end
34
- stop ||= @arranger.finished?
35
40
  end
36
41
  @text = @printed_lines.join ?\n
37
42
  @everything_printed = @arranger.finished?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.0.0.beta.1'
5
+ VERSION = '2.0.0.beta.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta.1
4
+ version: 2.0.0.beta.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-05-04 00:00:00.000000000 Z
12
+ date: 2022-05-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor
@@ -234,9 +234,12 @@ files:
234
234
  - data/themes/base-theme.yml
235
235
  - data/themes/default-for-print-theme.yml
236
236
  - data/themes/default-for-print-with-fallback-font-theme.yml
237
+ - data/themes/default-for-print-with-font-fallbacks-theme.yml
238
+ - data/themes/default-sans-theme.yml
239
+ - data/themes/default-sans-with-font-fallbacks-theme.yml
237
240
  - data/themes/default-theme.yml
238
241
  - data/themes/default-with-fallback-font-theme.yml
239
- - data/themes/sans-with-fallback-font-theme.yml
242
+ - data/themes/default-with-font-fallbacks-theme.yml
240
243
  - docs/theming-guide.adoc
241
244
  - lib/asciidoctor-pdf.rb
242
245
  - lib/asciidoctor/pdf.rb
@@ -264,12 +267,14 @@ files:
264
267
  - lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb
265
268
  - lib/asciidoctor/pdf/ext/prawn.rb
266
269
  - lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb
270
+ - lib/asciidoctor/pdf/ext/prawn/document/column_box.rb
267
271
  - lib/asciidoctor/pdf/ext/prawn/extensions.rb
268
272
  - lib/asciidoctor/pdf/ext/prawn/font/afm.rb
269
273
  - lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb
270
274
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb
271
275
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb
272
276
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb
277
+ - lib/asciidoctor/pdf/ext/prawn/formatted_text/indented_paragraph_wrap.rb
273
278
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb
274
279
  - lib/asciidoctor/pdf/ext/prawn/images.rb
275
280
  - lib/asciidoctor/pdf/ext/pygments.rb