asciidoctor-pdf 2.1.5 → 2.3.0

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.
@@ -23,4 +23,9 @@ class Asciidoctor::Document
23
23
  end
24
24
  nil
25
25
  end
26
+
27
+ # Internal: Returns whether the specified attribute has never been set and is not locked.
28
+ def attr_unspecified? name
29
+ !((attribute_locked? name) || (@attributes_modified.include? name))
30
+ end
26
31
  end
@@ -3,6 +3,10 @@
3
3
  Prawn::Document::ColumnBox.prepend (Module.new do
4
4
  attr_accessor :current_column
5
5
 
6
+ def last_column
7
+ @columns - 1
8
+ end
9
+
6
10
  def move_past_bottom
7
11
  (doc = @document).y = @y
8
12
  return if (@current_column = (@current_column + 1) % @columns) > 0
@@ -371,14 +371,16 @@ module Asciidoctor
371
371
  else
372
372
  super points.to_f
373
373
  end
374
- # NOTE: assume em value (since a font size of 1 is extremely unlikely)
375
- elsif points <= 1
376
- super @font_size * points
377
374
  else
378
375
  super points
379
376
  end
380
377
  end
381
378
 
379
+ def set_font font, size = nil
380
+ @font = font
381
+ font_size size if size
382
+ end
383
+
382
384
  def resolve_font_style styles
383
385
  if styles.include? :bold
384
386
  (styles.include? :italic) ? :bold_italic : :bold
@@ -1121,6 +1123,10 @@ module Asciidoctor
1121
1123
  # Note that if the block has content that itself requires a dry run, that nested dry run will
1122
1124
  # be performed in a separate scratch document.
1123
1125
  #
1126
+ # The block passed to dry run should take steps to avoid leaving the document state modified.
1127
+ # This can be done by calling `push_scratch doc` at the start of the block and `pop_scratch`
1128
+ # in the ensure clause of the block.
1129
+ #
1124
1130
  # options - A Hash of options that configure the dry run computation:
1125
1131
  # :keep_together - A Boolean indicating whether an attempt should be made to keep
1126
1132
  # the content on the same page (optional, default: false).
@@ -1133,7 +1139,7 @@ module Asciidoctor
1133
1139
  #
1134
1140
  # Returns an Extent or ScratchExtent object that describes the bounds of the content block.
1135
1141
  def dry_run keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block
1136
- (scratch_pdf = scratch).start_new_page layout: page.layout
1142
+ (scratch_pdf = scratch).start_new_page layout: page.layout, margin: page_margin
1137
1143
  saved_bounds = scratch_pdf.bounds
1138
1144
  scratch_pdf.bounds = bounds.dup.tap do |bounds_copy|
1139
1145
  bounds_copy.instance_variable_set :@document, scratch_pdf
@@ -26,6 +26,17 @@ Prawn::Text::Formatted::Arranger.prepend (Module.new do
26
26
  (string = super) == @dummy_text ? (string.extend Prawn::Text::NoopLstripBang) : string
27
27
  end
28
28
 
29
+ def preview_joined_string
30
+ if (next_unconsumed = @unconsumed[0] || {})[:wj] && !(@consumed[-1] || [])[:wj]
31
+ idx = 0
32
+ str = '' if (str = next_unconsumed[:text]) == @dummy_text
33
+ while (next_unconsumed = @unconsumed[idx += 1] || {})[:wj] && (next_string = next_unconsumed[:text])
34
+ str += next_string unless next_string == @dummy_text
35
+ end
36
+ str unless str == ''
37
+ end
38
+ end
39
+
29
40
  def apply_font_size size, styles
30
41
  if (subscript? styles) || (superscript? styles)
31
42
  size ||= @document.font_size
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ Prawn::Text::Formatted::LineWrap.prepend (Module.new do
4
+ def add_fragment_to_line fragment
5
+ case fragment
6
+ when ''
7
+ true
8
+ when ?\n
9
+ @newline_encountered = true
10
+ false
11
+ else
12
+ if (joined_string = @arranger.preview_joined_string)
13
+ joined_string_width = @document.width_of (tokenize joined_string)[0], kerning: @kerning
14
+ else
15
+ joined_string_width = 0
16
+ end
17
+ last_idx = (segments = tokenize fragment).length - 1
18
+ segments.each_with_index do |segment, idx|
19
+ if segment == (zero_width_space segment.encoding)
20
+ segment_width = effective_segment_width = 0
21
+ else
22
+ segment_width = effective_segment_width = @document.width_of segment, kerning: @kerning
23
+ effective_segment_width += joined_string_width if idx === last_idx
24
+ end
25
+ if @accumulated_width + effective_segment_width <= @width
26
+ @accumulated_width += segment_width
27
+ if segment[-1] == (shy = soft_hyphen segment.encoding)
28
+ @accumulated_width -= (@document.width_of shy, kerning: @kerning)
29
+ end
30
+ @fragment_output += segment
31
+ else
32
+ @line_contains_more_than_one_word = false if @accumulated_width == 0 && @line_contains_more_than_one_word
33
+ end_of_the_line_reached segment
34
+ fragment_finished fragment
35
+ return false
36
+ end
37
+ end
38
+ fragment_finished fragment
39
+ true
40
+ end
41
+ end
42
+ end)
@@ -13,5 +13,6 @@ require_relative 'prawn/formatted_text/arranger'
13
13
  require_relative 'prawn/formatted_text/box'
14
14
  require_relative 'prawn/formatted_text/fragment'
15
15
  require_relative 'prawn/formatted_text/indented_paragraph_wrap'
16
+ require_relative 'prawn/formatted_text/line_wrap'
16
17
  require_relative 'prawn/formatted_text/protect_bottom_gutter'
17
18
  require_relative 'prawn/extensions'
@@ -315,10 +315,12 @@ module Asciidoctor
315
315
  end) : value
316
316
  elsif (value = attrs[:id])
317
317
  # NOTE: text is null character, which is used as placeholder text so Prawn doesn't drop fragment
318
- fragment = { name: value, callback: [InlineDestinationMarker] }
318
+ new_fragment = { name: value, callback: [InlineDestinationMarker] }
319
+ new_fragment[:wj] = true if fragment[:wj]
319
320
  if (type = attrs[:type])
320
- fragment[:type] = type.to_sym
321
+ new_fragment[:type] = type.to_sym
321
322
  end
323
+ fragment = new_fragment
322
324
  visible = nil
323
325
  end
324
326
  end
@@ -357,6 +359,7 @@ module Asciidoctor
357
359
  end
358
360
  # TODO: we could limit to select tags, but doesn't seem to really affect performance
359
361
  attrs[:class].split.each do |class_name|
362
+ fragment[:wj] = true if class_name == 'wj'
360
363
  next unless @theme_settings.key? class_name
361
364
  update_fragment fragment, @theme_settings[class_name]
362
365
  # NOTE: defer assignment of callback since we must look at combined styles of element and role
@@ -8,7 +8,7 @@ module Asciidoctor
8
8
  '&gt;' => '>',
9
9
  '&amp;' => '&',
10
10
  }
11
- XMLSpecialCharsRx = /(?:#{XMLSpecialChars.keys.join '|'})/
11
+ XMLSpecialCharsRx = /&(?:[lg]t|amp);/
12
12
  InverseXMLSpecialChars = XMLSpecialChars.invert
13
13
  InverseXMLSpecialCharsRx = /[#{InverseXMLSpecialChars.keys.join}]/
14
14
  (BuiltInNamedEntities = {
@@ -28,16 +28,20 @@ module Asciidoctor
28
28
  #
29
29
  # FIXME: move to a module so we can mix it in elsewhere
30
30
  # FIXME: add option to control escaping entities, or a filter mechanism in general
31
- def sanitize string
31
+ def sanitize string, compact: true
32
32
  string = string.gsub SanitizeXMLRx, '' if string.include? '<'
33
33
  string = string.gsub(CharRefRx) { $1 ? BuiltInNamedEntities[$1] : ([$2 ? $2.to_i : ($3.to_i 16)].pack 'U1') } if string.include? '&'
34
- string.strip.tr_s ' ', ' '
34
+ compact ? (string.strip.tr_s ' ', ' ') : string
35
35
  end
36
36
 
37
37
  def escape_xml string
38
38
  string.gsub InverseXMLSpecialCharsRx, InverseXMLSpecialChars
39
39
  end
40
40
 
41
+ def unescape_xml string
42
+ string.gsub XMLSpecialCharsRx, XMLSpecialChars
43
+ end
44
+
41
45
  def escape_amp string
42
46
  string.gsub UnescapedAmpersandRx, '&amp;'
43
47
  end
@@ -160,7 +160,7 @@ module Asciidoctor
160
160
  data[key] = {}.tap do |accum|
161
161
  val.each do |key2, val2|
162
162
  key2 = key2.tr '-', '_' if key2.include? '-'
163
- accum[key2.to_sym] = (key2.end_with? '_color') ? (to_color evaluate val2, data) : (evaluate val2, data)
163
+ accum[key2.to_sym] = (key2.end_with? '_color') ? (to_color evaluate val2, data, math: false) : (evaluate val2, data)
164
164
  end
165
165
  end if val
166
166
  elsif ::Hash === val
@@ -173,20 +173,18 @@ module Asciidoctor
173
173
  end
174
174
  elsif (rekey = DeprecatedKeys[key]) ||
175
175
  ((key.start_with? 'role_') && (key.end_with? '_align') && (rekey = key.sub RoleAlignKeyRx, '_text_align'))
176
- data[rekey] = evaluate val, data
176
+ data[rekey] = evaluate val, data, math: false
177
177
  elsif PaddingBottomHackKeys.include? key
178
178
  val = evaluate val, data
179
179
  # normalize padding hacks for themes designed before the converter had smart margins
180
180
  val[2] = val[0] if ::Array === val && val[0].to_f >= 0 && val[2].to_f <= 0
181
181
  data[key] = val
182
- # QUESTION: do we really need to evaluate_math in this case?
183
182
  elsif key.end_with? '_color'
184
- if key == 'table_border_color'
185
- data[key] = ::Array === val ? val.map {|it| to_color evaluate it, data } : (to_color evaluate val, data)
186
- elsif key == 'table_grid_color' && ::Array === val && val.size == 2
187
- data[key] = val.map {|it| to_color evaluate it, data }
183
+ # assume table_grid_color is a single color unless the value is a 2-element array for backwards compatibility
184
+ if key == 'table_border_color' ? ::Array === val : (key == 'table_grid_color' && ::Array === val && val.size == 2)
185
+ data[key] = val.map {|it| to_color evaluate it, data, math: false }
188
186
  else
189
- data[key] = to_color evaluate val, data
187
+ data[key] = to_color evaluate val, data, math: false
190
188
  end
191
189
  elsif key.end_with? '_content'
192
190
  data[key] = (expand_vars val.to_s, data).to_s
@@ -196,12 +194,12 @@ module Asciidoctor
196
194
  data
197
195
  end
198
196
 
199
- def evaluate expr, vars
197
+ def evaluate expr, vars, math: true
200
198
  case expr
201
199
  when ::String
202
- evaluate_math expand_vars expr, vars
200
+ math ? (evaluate_math expand_vars expr, vars) : (expand_vars expr, vars)
203
201
  when ::Array
204
- expr.map {|e| evaluate e, vars }
202
+ expr.map {|e| evaluate e, vars, math: math }
205
203
  else
206
204
  expr
207
205
  end
@@ -233,7 +231,6 @@ module Asciidoctor
233
231
  def evaluate_math expr
234
232
  return expr if !(::String === expr) || ColorValue === expr
235
233
  # resolve measurement values (e.g., 0.5in => 36)
236
- # QUESTION: should we round the value? perhaps leave that to the precision functions
237
234
  # NOTE: leave % as a string; handled by converter for now
238
235
  original, expr = expr, (resolve_measurement_values expr)
239
236
  while true
@@ -257,8 +254,7 @@ module Asciidoctor
257
254
  end
258
255
  end
259
256
  if (expr.end_with? ')') && expr =~ PrecisionFuncRx
260
- op = $1
261
- offset = op.length + 1
257
+ offset = (op = $1).length + 1
262
258
  expr = expr[offset...-1].to_f.send op.to_sym
263
259
  end
264
260
  if expr == original
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.1.5'
5
+ VERSION = '2.3.0'
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.1.5
4
+ version: 2.3.0
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-07-10 00:00:00.000000000 Z
12
+ date: 2022-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor
@@ -280,6 +280,7 @@ files:
280
280
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb
281
281
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb
282
282
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/indented_paragraph_wrap.rb
283
+ - lib/asciidoctor/pdf/ext/prawn/formatted_text/line_wrap.rb
283
284
  - lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb
284
285
  - lib/asciidoctor/pdf/ext/prawn/images.rb
285
286
  - lib/asciidoctor/pdf/ext/pygments.rb