hexapdf 0.39.0 → 0.40.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0a43d232528df9bfc4a2c9baddd9cd1ddbd33fe7cce9d146b4e25760f25429b
4
- data.tar.gz: 37cb10752d22bbc89fd18a779152ef7b5e02e6237318006a4b0e0a420d2890e2
3
+ metadata.gz: 2dab266d2115bdd9a7c9caf6a7512b56da77c14b8fe080d631d270c89a67e49f
4
+ data.tar.gz: c05acdf542d3b65e2c763f9aa84e21de4ad4f6800a48a4b4ca6873832089a0e2
5
5
  SHA512:
6
- metadata.gz: 79a27b101c502261e1bca7a25fa26fa434d38cec09a2ccb28a698a4364d8ed337ee63d82ce8cd4dd3097334ed54f0877565c25e20c2494c0ae7029156dc188ef
7
- data.tar.gz: 69befc3a7066eb90a58ad4a65243939930f26ecc461e0f6f7c9bf0894ddfa58bf1a02567563caa453b0c6e745421de75e7dd433926d2a56b96aa4d71557059f5
6
+ metadata.gz: 0e63528c1c604b06a8f07a53852ebfc2f5172a9aee43320942e4088f8aaf68953acc6f9e6017c4215591a8bb7a428b61fa20bd6e4ea180af39c62058de5b04db
7
+ data.tar.gz: 8b648570a98fcd5f1688c97ead5c05a0da6918cba49b3905bd70f526a65ddf376618e5d533c6bb04823117fc892839a600d0ba63d006699205e1ef399e0b64f5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## 0.40.0 - 2024-03-23
2
+
3
+ ### Changed
4
+
5
+ * **Breaking change**: Style property 'text_overflow' is now called 'overflow'
6
+
7
+ ### Fixed
8
+
9
+ * [HexaPDF::Layout::ListBox] to hide marker in case of splitting list items with
10
+ multiple boxes
11
+ * [HexaPDF::Layout::ListBox] to create independent marker boxes for all markers
12
+ * [HexaPDF::Layout::ListBox] to correctly respect a set height
13
+
14
+
15
+ ## 0.39.1 - 2024-03-20
16
+
17
+ ### Fixed
18
+
19
+ * [HexaPDF::Layout::TableBox] to correctly split tables when a row span with a
20
+ too high cell is involved
21
+
22
+
1
23
  ## 0.39.0 - 2024-03-18
2
24
 
3
25
  ### Added
@@ -255,7 +255,9 @@ module HexaPDF
255
255
 
256
256
  @draw_pos_x = frame.x + reserved_width_left
257
257
  @draw_pos_y = frame.y - @height + reserved_height_bottom
258
- @fit_successful = @results.all? {|r| r.box_fitter.fit_successful? } && @results.size == @children.size
258
+ @all_items_fitted = @results.all? {|r| r.box_fitter.fit_successful? } &&
259
+ @results.size == @children.size
260
+ @fit_successful = @all_items_fitted || (@initial_height > 0 && style.overflow == :truncate)
259
261
  end
260
262
 
261
263
  private
@@ -307,7 +309,7 @@ module HexaPDF
307
309
  # Splits the content of the list box. This method is called from Box#split.
308
310
  def split_content(_available_width, _available_height, _frame)
309
311
  remaining_boxes = @results[-1].box_fitter.remaining_boxes
310
- first_is_split_box = remaining_boxes.first&.split_box?
312
+ first_is_split_box = !remaining_boxes.empty?
311
313
  children = (remaining_boxes.empty? ? [] : [remaining_boxes]) + @children[@results.size..-1]
312
314
 
313
315
  box = create_split_box(split_box_value: first_is_split_box ? :hide_first_marker : :show_first_marker)
@@ -323,42 +325,47 @@ module HexaPDF
323
325
  # its contents.
324
326
  def item_marker_box(document, index)
325
327
  return @marker_type.call(document, self, index) if @marker_type.kind_of?(Proc)
326
- return @item_marker_box if defined?(@item_marker_box)
327
-
328
- marker_style = {
329
- font: style.font? ? style.font : document.fonts.add("Times"),
330
- font_size: style.font_size || 10, fill_color: style.fill_color
331
- }
332
- fragment = case @marker_type
333
- when :disc
334
- TextFragment.create("•", marker_style)
335
- when :circle
336
- unless marker_style[:font].decode_codepoint("❍".ord).valid?
337
- marker_style[:font] = document.fonts.add("ZapfDingbats")
338
- end
339
- TextFragment.create("❍", **marker_style,
340
- font_size: style.font_size / 2.0,
341
- text_rise: -style.font_size / 1.8)
342
- when :square
343
- unless marker_style[:font].decode_codepoint("■".ord).valid?
344
- marker_style[:font] = document.fonts.add("ZapfDingbats")
328
+
329
+ unless (fragment = @item_marker_fragment)
330
+ marker_style = {
331
+ font: style.font? ? style.font : document.fonts.add("Times"),
332
+ font_size: style.font_size || 10, fill_color: style.fill_color
333
+ }
334
+ fragment = case @marker_type
335
+ when :disc
336
+ TextFragment.create("•", marker_style)
337
+ when :circle
338
+ unless marker_style[:font].decode_codepoint("❍".ord).valid?
339
+ marker_style[:font] = document.fonts.add("ZapfDingbats")
340
+ end
341
+ TextFragment.create("❍", **marker_style,
342
+ font_size: style.font_size / 2.0,
343
+ text_rise: -style.font_size / 1.8)
344
+ when :square
345
+ unless marker_style[:font].decode_codepoint("■".ord).valid?
346
+ marker_style[:font] = document.fonts.add("ZapfDingbats")
347
+ end
348
+ TextFragment.create("■", **marker_style,
349
+ font_size: style.font_size / 2.0,
350
+ text_rise: -style.font_size / 1.8)
351
+ when :decimal
352
+ text = (@start_number + index).to_s << "."
353
+ TextFragment.create(text, marker_style)
354
+ else
355
+ raise HexaPDF::Error, "Unknown list marker type #{@marker_type.inspect}"
345
356
  end
346
- TextFragment.create("■", **marker_style,
347
- font_size: style.font_size / 2.0,
348
- text_rise: -style.font_size / 1.8)
349
- when :decimal
350
- text = (@start_number + index).to_s << "."
351
- TextFragment.create(text, marker_style)
352
- else
353
- raise HexaPDF::Error, "Unknown list marker type #{@marker_type.inspect}"
354
- end
355
- box = TextBox.new(items: [fragment], style: {text_align: :right, padding: [0, 5, 0, 0]})
356
- @item_marker_box = box unless @marker_type == :decimal
357
- box
357
+ @item_marker_fragment = fragment unless @marker_type == :decimal
358
+ end
359
+ TextBox.new(items: [fragment], style: {text_align: :right, padding: [0, 5, 0, 0]})
358
360
  end
359
361
 
360
362
  # Draws the list items onto the canvas at position [x, y].
361
363
  def draw_content(canvas, x, y)
364
+ if !@all_items_fitted && (@initial_height > 0 && style.overflow == :error)
365
+ raise HexaPDF::Error, "Some items don't fit into box with limited height and " \
366
+ "style property overflow is set to :error"
367
+ end
368
+
362
369
  translate = style.position != :flow && (x != @draw_pos_x || y != @draw_pos_y)
363
370
 
364
371
  if translate
@@ -1084,25 +1084,6 @@ module HexaPDF
1084
1084
  # 'Centered',
1085
1085
  # {text: "\u{00a0}", fill_horizontal: 1, overlays: overlays}])
1086
1086
 
1087
- ##
1088
- # :method: text_overflow
1089
- # :call-seq:
1090
- # text_overflow(mode = nil)
1091
- #
1092
- # Specifies how text overflowing a box with a given initial height should be handled:
1093
- #
1094
- # Possible values:
1095
- #
1096
- # :error:: An error is raised (default).
1097
- # :truncate:: Truncates the overflowing text.
1098
- #
1099
- # Examples:
1100
- #
1101
- # #>pdf-composer100
1102
- # composer.text("This is some longer text that does appear in two lines.")
1103
- # composer.text("This is some longer text that does not appear in two lines.",
1104
- # height: 15, text_overflow: :truncate)
1105
-
1106
1087
  ##
1107
1088
  # :method: background_color
1108
1089
  # :call-seq:
@@ -1414,6 +1395,26 @@ module HexaPDF
1414
1395
  # composer.text('Mask covers everything', mask_mode: :fill)
1415
1396
  # composer.text('On the next page')
1416
1397
 
1398
+ ##
1399
+ # :method: overflow
1400
+ # :call-seq:
1401
+ # overflow(mode = nil)
1402
+ #
1403
+ # Specifies how overflowing boxes (e.g. the text of a box or the children of a container) with
1404
+ # a given initial height should be handled:
1405
+ #
1406
+ # Possible values:
1407
+ #
1408
+ # :error:: An error is raised (default).
1409
+ # :truncate:: Truncates the overflowing parts.
1410
+ #
1411
+ # Examples:
1412
+ #
1413
+ # #>pdf-composer100
1414
+ # composer.text("This is some longer text that does appear in two lines.")
1415
+ # composer.text("This is some longer text that does not appear in two lines.",
1416
+ # height: 15, text_overflow: :truncate)
1417
+
1417
1418
  [
1418
1419
  [:font, "raise HexaPDF::Error, 'No font set'"],
1419
1420
  [:font_size, 10],
@@ -1454,7 +1455,6 @@ module HexaPDF
1454
1455
  extra_args: ", extra_arg = nil"}],
1455
1456
  [:last_line_gap, false, {valid_values: [true, false]}],
1456
1457
  [:fill_horizontal, nil],
1457
- [:text_overflow, :error],
1458
1458
  [:background_color, nil],
1459
1459
  [:background_alpha, 1],
1460
1460
  [:padding, "Quad.new(0)", {setter: "Quad.new(value)"}],
@@ -1467,6 +1467,7 @@ module HexaPDF
1467
1467
  [:valign, :top, {valid_values: [:top, :center, :bottom]}],
1468
1468
  [:mask_mode, :default, {valid_values: [:default, :none, :box, :fill_horizontal,
1469
1469
  :fill_frame_horizontal, :fill_vertical, :fill]}],
1470
+ [:overflow, :error],
1470
1471
  ].each do |name, default, options = {}|
1471
1472
  default = default.inspect unless default.kind_of?(String)
1472
1473
  setter = options.delete(:setter) || "value"
@@ -417,7 +417,8 @@ module HexaPDF
417
417
  break
418
418
  end
419
419
  end
420
- [height - available_height, last_fitted_row_index]
420
+
421
+ [height - available_height, last_fitted_row_index < start_row ? -1 : last_fitted_row_index]
421
422
  end
422
423
 
423
424
  # Draws the rows from +start_row+ to +end_row+ on the given +canvas+, with the top-left
@@ -647,7 +648,7 @@ module HexaPDF
647
648
  end
648
649
  end
649
650
 
650
- # Splits the content of the column box. This method is called from Box#split.
651
+ # Splits the content of the table box. This method is called from Box#split.
651
652
  def split_content(_available_width, _available_height, _frame)
652
653
  if @special_cells_fit_not_successful || @last_fitted_row_index < 0
653
654
  [nil, self]
@@ -106,7 +106,7 @@ module HexaPDF
106
106
  end
107
107
 
108
108
  @result.status == :success ||
109
- (@result.status == :height && @initial_height > 0 && style.text_overflow == :truncate)
109
+ (@result.status == :height && @initial_height > 0 && style.overflow == :truncate)
110
110
  end
111
111
 
112
112
  # Splits the text box into two boxes if necessary and possible.
@@ -136,9 +136,9 @@ module HexaPDF
136
136
  def draw_content(canvas, x, y)
137
137
  return unless @result
138
138
 
139
- if @result.status == :height && @initial_height > 0 && style.text_overflow == :error
139
+ if @result.status == :height && @initial_height > 0 && style.overflow == :error
140
140
  raise HexaPDF::Error, "Text doesn't fit into box with limited height and " \
141
- "style property text_overflow is set to :error"
141
+ "style property overflow is set to :error"
142
142
  end
143
143
 
144
144
  return if @result.lines.empty?
@@ -284,7 +284,7 @@ module HexaPDF
284
284
  end
285
285
 
286
286
  # Creates a new widget annotation for this form field (must be a terminal field!) on the
287
- # given +page+, adding the +values+ to the created widget annotation oject.
287
+ # given +page+, adding the +values+ to the created widget annotation object.
288
288
  #
289
289
  # If +allow_embedded+ is +false+, embedding the first widget in the field itself is not
290
290
  # allowed.
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.39.0'
40
+ VERSION = '0.40.0'
41
41
 
42
42
  end
@@ -73,6 +73,12 @@ describe HexaPDF::Layout::ListBox do
73
73
  check_box(box, 100, 40)
74
74
  end
75
75
 
76
+ it "respects the set initial height and the property overflow=:truncate" do
77
+ box = create_box(children: @text_boxes[0, 2], height: 20,
78
+ style: {overflow: :truncate, position: position})
79
+ check_box(box, 100, 20)
80
+ end
81
+
76
82
  it "respects the border and padding around all list items, position #{position}" do
77
83
  box = create_box(children: @text_boxes[0, 2],
78
84
  style: {border: {width: [5, 4, 3, 2]}, padding: [5, 4, 3, 2], position: position})
@@ -108,7 +114,14 @@ describe HexaPDF::Layout::ListBox do
108
114
  check_box(box, 100, 70, [[10, 80], [10, 30]])
109
115
  end
110
116
 
111
- it "fails for unknown item types" do
117
+ it "creates a new box for each marker even if the marker is the same" do
118
+ box = create_box(children: @text_boxes[0, 2])
119
+ check_box(box, 100, 40)
120
+ results = box.instance_variable_get(:@results)
121
+ refute_same(results[0].marker, results[1].marker)
122
+ end
123
+
124
+ it "fails for unknown marker types" do
112
125
  box = create_box(children: @text_boxes[0, 1], marker_type: :unknown)
113
126
  assert_raises(HexaPDF::Error) { box.fit(100, 100, @frame) }
114
127
  end
@@ -136,6 +149,17 @@ describe HexaPDF::Layout::ListBox do
136
149
  assert_equal(2, box_b.children.size)
137
150
  assert_equal(1, box_b.start_number)
138
151
  end
152
+
153
+ it "splits a list item containg multiple boxes along box lines" do
154
+ box = create_box(children: [@text_boxes[0], @text_boxes[1, 2]])
155
+ box.fit(100, 40, @frame)
156
+ box_a, box_b = box.split(100, 40, @frame)
157
+ assert_same(box, box_a)
158
+ assert_equal(:hide_first_marker, box_b.split_box?)
159
+ assert_equal(1, box_a.instance_variable_get(:@results)[1].box_fitter.fit_results.size)
160
+ assert_equal(1, box_b.children.size)
161
+ assert_equal(2, box_b.start_number)
162
+ end
139
163
  end
140
164
 
141
165
  describe "draw" do
@@ -315,5 +339,10 @@ describe HexaPDF::Layout::ListBox do
315
339
  assert_equal(:ZapfDingbats, @canvas.resources.font(:F1)[:BaseFont])
316
340
  end
317
341
 
342
+ it "fails if the initial height is set and property overflow is set to :error" do
343
+ box = create_box(children: @fixed_size_boxes[0, 2], height: 10)
344
+ box.fit(100, 100, @frame)
345
+ assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 100 - box.height) }
346
+ end
318
347
  end
319
348
  end
@@ -783,7 +783,7 @@ describe HexaPDF::Layout::Style do
783
783
  refute(@style.superscript)
784
784
  refute(@style.last_line_gap)
785
785
  refute(@style.fill_horizontal)
786
- assert_equal(:error, @style.text_overflow)
786
+ assert_equal(:error, @style.overflow)
787
787
  assert_kind_of(HexaPDF::Layout::Style::Layers, @style.underlays)
788
788
  assert_kind_of(HexaPDF::Layout::Style::Layers, @style.overlays)
789
789
  assert_equal(:default, @style.position)
@@ -362,8 +362,8 @@ describe HexaPDF::Layout::TableBox do
362
362
  @doc = HexaPDF::Document.new
363
363
  @page = @doc.pages.add
364
364
  @frame = HexaPDF::Layout::Frame.new(0, 0, 160, 100, context: @page)
365
- draw_block = lambda {|canvas, _box| canvas.move_to(0, 0).end_path }
366
- @fixed_size_boxes = 15.times.map { HexaPDF::Layout::Box.new(width: 20, height: 10, &draw_block) }
365
+ @draw_block = lambda {|canvas, _box| canvas.move_to(0, 0).end_path }
366
+ @fixed_size_boxes = 15.times.map { HexaPDF::Layout::Box.new(width: 20, height: 10, &@draw_block) }
367
367
  end
368
368
 
369
369
  def create_box(**kwargs)
@@ -561,6 +561,30 @@ describe HexaPDF::Layout::TableBox do
561
561
  assert_equal(-1, box_b.last_fitted_row_index)
562
562
  end
563
563
 
564
+ it "splits the table correctly when row spans and a too-high cell are involved" do
565
+ cells = [[@fixed_size_boxes[0], @fixed_size_boxes[1]],
566
+ [{row_span: 2, content: @fixed_size_boxes[2]}, @fixed_size_boxes[3]],
567
+ [HexaPDF::Layout::Box.new(width: 20, height: 150, &@draw_block)]]
568
+ box = create_box(cells: cells)
569
+
570
+ refute(box.fit(100, 100, @frame))
571
+ box_a, box_b = box.split(100, 100, @frame)
572
+ assert_same(box_a, box)
573
+ assert(box_b.split_box?)
574
+ assert_equal(0, box_a.start_row_index)
575
+ assert_equal(0, box_a.last_fitted_row_index)
576
+ assert_equal(1, box_b.start_row_index)
577
+ assert_equal(-1, box_b.last_fitted_row_index)
578
+
579
+ refute(box_b.fit(100, 100, @frame))
580
+ box_c, box_d = box_b.split(100, 100, @frame)
581
+ assert_nil(box_c)
582
+ assert_same(box_d, box_b)
583
+ assert(box_d.split_box?)
584
+ assert_equal(1, box_d.start_row_index)
585
+ assert_equal(-1, box_d.last_fitted_row_index)
586
+ end
587
+
564
588
  it "splits the table if the header or footer rows don't fit" do
565
589
  cells_creator = lambda {|_| [@fixed_size_boxes[10, 2]] }
566
590
  [{header: cells_creator}, {footer: cells_creator}].each do |args|
@@ -79,13 +79,13 @@ describe HexaPDF::Layout::TextBox do
79
79
  end
80
80
  end
81
81
 
82
- it "respects the style property text_overflow when fitting too much text" do
82
+ it "respects the style property overflow when fitting too much text" do
83
83
  box = create_box([@inline_box] * 20, height: 15)
84
84
  refute(box.fit(100, 100, @frame))
85
- box.style.text_overflow = :truncate
85
+ box.style.overflow = :truncate
86
86
  assert(box.fit(100, 100, @frame))
87
87
 
88
- box = create_box([@inline_box] * 20, style: {text_overflow: :truncate})
88
+ box = create_box([@inline_box] * 20, style: {overflow: :truncate})
89
89
  refute(box.fit(100, 15, @frame))
90
90
  end
91
91
 
@@ -196,7 +196,7 @@ describe HexaPDF::Layout::TextBox do
196
196
  assert_operators(@canvas.contents, [])
197
197
  end
198
198
 
199
- it "raises an error if there is too much content for a set height with text_overlow=:error" do
199
+ it "raises an error if there is too much content for a set height with overflow=:error" do
200
200
  box = create_box([@inline_box] * 20, height: 15)
201
201
  box.fit(100, 100, @frame)
202
202
  assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 0) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.39.0
4
+ version: 0.40.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-18 00:00:00.000000000 Z
11
+ date: 2024-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse