asciidoctor-pdf 2.1.5 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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