hexapdf 0.39.0 → 0.40.0

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